162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci*******************************************************************************
462306a36Sopenharmony_ci**
562306a36Sopenharmony_ci**  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.
662306a36Sopenharmony_ci**
762306a36Sopenharmony_ci**
862306a36Sopenharmony_ci*******************************************************************************
962306a36Sopenharmony_ci******************************************************************************/
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/pagemap.h>
1262306a36Sopenharmony_ci#include <linux/seq_file.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/ctype.h>
1562306a36Sopenharmony_ci#include <linux/debugfs.h>
1662306a36Sopenharmony_ci#include <linux/slab.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "dlm_internal.h"
1962306a36Sopenharmony_ci#include "midcomms.h"
2062306a36Sopenharmony_ci#include "lock.h"
2162306a36Sopenharmony_ci#include "ast.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define DLM_DEBUG_BUF_LEN 4096
2462306a36Sopenharmony_cistatic char debug_buf[DLM_DEBUG_BUF_LEN];
2562306a36Sopenharmony_cistatic struct mutex debug_buf_lock;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic struct dentry *dlm_root;
2862306a36Sopenharmony_cistatic struct dentry *dlm_comms;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic char *print_lockmode(int mode)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	switch (mode) {
3362306a36Sopenharmony_ci	case DLM_LOCK_IV:
3462306a36Sopenharmony_ci		return "--";
3562306a36Sopenharmony_ci	case DLM_LOCK_NL:
3662306a36Sopenharmony_ci		return "NL";
3762306a36Sopenharmony_ci	case DLM_LOCK_CR:
3862306a36Sopenharmony_ci		return "CR";
3962306a36Sopenharmony_ci	case DLM_LOCK_CW:
4062306a36Sopenharmony_ci		return "CW";
4162306a36Sopenharmony_ci	case DLM_LOCK_PR:
4262306a36Sopenharmony_ci		return "PR";
4362306a36Sopenharmony_ci	case DLM_LOCK_PW:
4462306a36Sopenharmony_ci		return "PW";
4562306a36Sopenharmony_ci	case DLM_LOCK_EX:
4662306a36Sopenharmony_ci		return "EX";
4762306a36Sopenharmony_ci	default:
4862306a36Sopenharmony_ci		return "??";
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,
5362306a36Sopenharmony_ci			       struct dlm_rsb *res)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (lkb->lkb_status == DLM_LKSTS_CONVERT ||
5862306a36Sopenharmony_ci	    lkb->lkb_status == DLM_LKSTS_WAITING)
5962306a36Sopenharmony_ci		seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	if (lkb->lkb_nodeid) {
6262306a36Sopenharmony_ci		if (lkb->lkb_nodeid != res->res_nodeid)
6362306a36Sopenharmony_ci			seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
6462306a36Sopenharmony_ci				   lkb->lkb_remid);
6562306a36Sopenharmony_ci		else
6662306a36Sopenharmony_ci			seq_printf(s, " Master:     %08x", lkb->lkb_remid);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (lkb->lkb_wait_type)
7062306a36Sopenharmony_ci		seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	seq_putc(s, '\n');
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void print_format1(struct dlm_rsb *res, struct seq_file *s)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	struct dlm_lkb *lkb;
7862306a36Sopenharmony_ci	int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	lock_rsb(res);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	for (i = 0; i < res->res_length; i++) {
8562306a36Sopenharmony_ci		if (isprint(res->res_name[i]))
8662306a36Sopenharmony_ci			seq_printf(s, "%c", res->res_name[i]);
8762306a36Sopenharmony_ci		else
8862306a36Sopenharmony_ci			seq_printf(s, "%c", '.');
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (res->res_nodeid > 0)
9262306a36Sopenharmony_ci		seq_printf(s, "\"\nLocal Copy, Master is node %d\n",
9362306a36Sopenharmony_ci			   res->res_nodeid);
9462306a36Sopenharmony_ci	else if (res->res_nodeid == 0)
9562306a36Sopenharmony_ci		seq_puts(s, "\"\nMaster Copy\n");
9662306a36Sopenharmony_ci	else if (res->res_nodeid == -1)
9762306a36Sopenharmony_ci		seq_printf(s, "\"\nLooking up master (lkid %x)\n",
9862306a36Sopenharmony_ci			   res->res_first_lkid);
9962306a36Sopenharmony_ci	else
10062306a36Sopenharmony_ci		seq_printf(s, "\"\nInvalid master %d\n", res->res_nodeid);
10162306a36Sopenharmony_ci	if (seq_has_overflowed(s))
10262306a36Sopenharmony_ci		goto out;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* Print the LVB: */
10562306a36Sopenharmony_ci	if (res->res_lvbptr) {
10662306a36Sopenharmony_ci		seq_puts(s, "LVB: ");
10762306a36Sopenharmony_ci		for (i = 0; i < lvblen; i++) {
10862306a36Sopenharmony_ci			if (i == lvblen / 2)
10962306a36Sopenharmony_ci				seq_puts(s, "\n     ");
11062306a36Sopenharmony_ci			seq_printf(s, "%02x ",
11162306a36Sopenharmony_ci				   (unsigned char) res->res_lvbptr[i]);
11262306a36Sopenharmony_ci		}
11362306a36Sopenharmony_ci		if (rsb_flag(res, RSB_VALNOTVALID))
11462306a36Sopenharmony_ci			seq_puts(s, " (INVALID)");
11562306a36Sopenharmony_ci		seq_putc(s, '\n');
11662306a36Sopenharmony_ci		if (seq_has_overflowed(s))
11762306a36Sopenharmony_ci			goto out;
11862306a36Sopenharmony_ci	}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	root_list = !list_empty(&res->res_root_list);
12162306a36Sopenharmony_ci	recover_list = !list_empty(&res->res_recover_list);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	if (root_list || recover_list) {
12462306a36Sopenharmony_ci		seq_printf(s, "Recovery: root %d recover %d flags %lx count %d\n",
12562306a36Sopenharmony_ci			   root_list, recover_list,
12662306a36Sopenharmony_ci			   res->res_flags, res->res_recover_locks_count);
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* Print the locks attached to this resource */
13062306a36Sopenharmony_ci	seq_puts(s, "Granted Queue\n");
13162306a36Sopenharmony_ci	list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) {
13262306a36Sopenharmony_ci		print_format1_lock(s, lkb, res);
13362306a36Sopenharmony_ci		if (seq_has_overflowed(s))
13462306a36Sopenharmony_ci			goto out;
13562306a36Sopenharmony_ci	}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	seq_puts(s, "Conversion Queue\n");
13862306a36Sopenharmony_ci	list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) {
13962306a36Sopenharmony_ci		print_format1_lock(s, lkb, res);
14062306a36Sopenharmony_ci		if (seq_has_overflowed(s))
14162306a36Sopenharmony_ci			goto out;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	seq_puts(s, "Waiting Queue\n");
14562306a36Sopenharmony_ci	list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) {
14662306a36Sopenharmony_ci		print_format1_lock(s, lkb, res);
14762306a36Sopenharmony_ci		if (seq_has_overflowed(s))
14862306a36Sopenharmony_ci			goto out;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	if (list_empty(&res->res_lookup))
15262306a36Sopenharmony_ci		goto out;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	seq_puts(s, "Lookup Queue\n");
15562306a36Sopenharmony_ci	list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
15662306a36Sopenharmony_ci		seq_printf(s, "%08x %s",
15762306a36Sopenharmony_ci			   lkb->lkb_id, print_lockmode(lkb->lkb_rqmode));
15862306a36Sopenharmony_ci		if (lkb->lkb_wait_type)
15962306a36Sopenharmony_ci			seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
16062306a36Sopenharmony_ci		seq_putc(s, '\n');
16162306a36Sopenharmony_ci		if (seq_has_overflowed(s))
16262306a36Sopenharmony_ci			goto out;
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci out:
16562306a36Sopenharmony_ci	unlock_rsb(res);
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,
16962306a36Sopenharmony_ci			       struct dlm_rsb *r)
17062306a36Sopenharmony_ci{
17162306a36Sopenharmony_ci	u64 xid = 0;
17262306a36Sopenharmony_ci	u64 us;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
17562306a36Sopenharmony_ci		if (lkb->lkb_ua)
17662306a36Sopenharmony_ci			xid = lkb->lkb_ua->xid;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* microseconds since lkb was added to current queue */
18062306a36Sopenharmony_ci	us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp));
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* id nodeid remid pid xid exflags flags sts grmode rqmode time_us
18362306a36Sopenharmony_ci	   r_nodeid r_len r_name */
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n",
18662306a36Sopenharmony_ci		   lkb->lkb_id,
18762306a36Sopenharmony_ci		   lkb->lkb_nodeid,
18862306a36Sopenharmony_ci		   lkb->lkb_remid,
18962306a36Sopenharmony_ci		   lkb->lkb_ownpid,
19062306a36Sopenharmony_ci		   (unsigned long long)xid,
19162306a36Sopenharmony_ci		   lkb->lkb_exflags,
19262306a36Sopenharmony_ci		   dlm_iflags_val(lkb),
19362306a36Sopenharmony_ci		   lkb->lkb_status,
19462306a36Sopenharmony_ci		   lkb->lkb_grmode,
19562306a36Sopenharmony_ci		   lkb->lkb_rqmode,
19662306a36Sopenharmony_ci		   (unsigned long long)us,
19762306a36Sopenharmony_ci		   r->res_nodeid,
19862306a36Sopenharmony_ci		   r->res_length,
19962306a36Sopenharmony_ci		   r->res_name);
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic void print_format2(struct dlm_rsb *r, struct seq_file *s)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct dlm_lkb *lkb;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	lock_rsb(r);
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
20962306a36Sopenharmony_ci		print_format2_lock(s, lkb, r);
21062306a36Sopenharmony_ci		if (seq_has_overflowed(s))
21162306a36Sopenharmony_ci			goto out;
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
21562306a36Sopenharmony_ci		print_format2_lock(s, lkb, r);
21662306a36Sopenharmony_ci		if (seq_has_overflowed(s))
21762306a36Sopenharmony_ci			goto out;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
22162306a36Sopenharmony_ci		print_format2_lock(s, lkb, r);
22262306a36Sopenharmony_ci		if (seq_has_overflowed(s))
22362306a36Sopenharmony_ci			goto out;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci out:
22662306a36Sopenharmony_ci	unlock_rsb(r);
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
23062306a36Sopenharmony_ci			      int rsb_lookup)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	u64 xid = 0;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
23562306a36Sopenharmony_ci		if (lkb->lkb_ua)
23662306a36Sopenharmony_ci			xid = lkb->lkb_ua->xid;
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n",
24062306a36Sopenharmony_ci		   lkb->lkb_id,
24162306a36Sopenharmony_ci		   lkb->lkb_nodeid,
24262306a36Sopenharmony_ci		   lkb->lkb_remid,
24362306a36Sopenharmony_ci		   lkb->lkb_ownpid,
24462306a36Sopenharmony_ci		   (unsigned long long)xid,
24562306a36Sopenharmony_ci		   lkb->lkb_exflags,
24662306a36Sopenharmony_ci		   dlm_iflags_val(lkb),
24762306a36Sopenharmony_ci		   lkb->lkb_status,
24862306a36Sopenharmony_ci		   lkb->lkb_grmode,
24962306a36Sopenharmony_ci		   lkb->lkb_rqmode,
25062306a36Sopenharmony_ci		   lkb->lkb_last_bast_mode,
25162306a36Sopenharmony_ci		   rsb_lookup,
25262306a36Sopenharmony_ci		   lkb->lkb_wait_type,
25362306a36Sopenharmony_ci		   lkb->lkb_lvbseq,
25462306a36Sopenharmony_ci		   (unsigned long long)ktime_to_ns(lkb->lkb_timestamp),
25562306a36Sopenharmony_ci		   (unsigned long long)ktime_to_ns(lkb->lkb_last_bast_time));
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic void print_format3(struct dlm_rsb *r, struct seq_file *s)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct dlm_lkb *lkb;
26162306a36Sopenharmony_ci	int i, lvblen = r->res_ls->ls_lvblen;
26262306a36Sopenharmony_ci	int print_name = 1;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	lock_rsb(r);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ",
26762306a36Sopenharmony_ci		   r,
26862306a36Sopenharmony_ci		   r->res_nodeid,
26962306a36Sopenharmony_ci		   r->res_first_lkid,
27062306a36Sopenharmony_ci		   r->res_flags,
27162306a36Sopenharmony_ci		   !list_empty(&r->res_root_list),
27262306a36Sopenharmony_ci		   !list_empty(&r->res_recover_list),
27362306a36Sopenharmony_ci		   r->res_recover_locks_count,
27462306a36Sopenharmony_ci		   r->res_length);
27562306a36Sopenharmony_ci	if (seq_has_overflowed(s))
27662306a36Sopenharmony_ci		goto out;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	for (i = 0; i < r->res_length; i++) {
27962306a36Sopenharmony_ci		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))
28062306a36Sopenharmony_ci			print_name = 0;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	seq_puts(s, print_name ? "str " : "hex");
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	for (i = 0; i < r->res_length; i++) {
28662306a36Sopenharmony_ci		if (print_name)
28762306a36Sopenharmony_ci			seq_printf(s, "%c", r->res_name[i]);
28862306a36Sopenharmony_ci		else
28962306a36Sopenharmony_ci			seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
29062306a36Sopenharmony_ci	}
29162306a36Sopenharmony_ci	seq_putc(s, '\n');
29262306a36Sopenharmony_ci	if (seq_has_overflowed(s))
29362306a36Sopenharmony_ci		goto out;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	if (!r->res_lvbptr)
29662306a36Sopenharmony_ci		goto do_locks;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	for (i = 0; i < lvblen; i++)
30162306a36Sopenharmony_ci		seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]);
30262306a36Sopenharmony_ci	seq_putc(s, '\n');
30362306a36Sopenharmony_ci	if (seq_has_overflowed(s))
30462306a36Sopenharmony_ci		goto out;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci do_locks:
30762306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
30862306a36Sopenharmony_ci		print_format3_lock(s, lkb, 0);
30962306a36Sopenharmony_ci		if (seq_has_overflowed(s))
31062306a36Sopenharmony_ci			goto out;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
31462306a36Sopenharmony_ci		print_format3_lock(s, lkb, 0);
31562306a36Sopenharmony_ci		if (seq_has_overflowed(s))
31662306a36Sopenharmony_ci			goto out;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
32062306a36Sopenharmony_ci		print_format3_lock(s, lkb, 0);
32162306a36Sopenharmony_ci		if (seq_has_overflowed(s))
32262306a36Sopenharmony_ci			goto out;
32362306a36Sopenharmony_ci	}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) {
32662306a36Sopenharmony_ci		print_format3_lock(s, lkb, 1);
32762306a36Sopenharmony_ci		if (seq_has_overflowed(s))
32862306a36Sopenharmony_ci			goto out;
32962306a36Sopenharmony_ci	}
33062306a36Sopenharmony_ci out:
33162306a36Sopenharmony_ci	unlock_rsb(r);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void print_format4(struct dlm_rsb *r, struct seq_file *s)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	int our_nodeid = dlm_our_nodeid();
33762306a36Sopenharmony_ci	int print_name = 1;
33862306a36Sopenharmony_ci	int i;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	lock_rsb(r);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	seq_printf(s, "rsb %p %d %d %d %d %lu %lx %d ",
34362306a36Sopenharmony_ci		   r,
34462306a36Sopenharmony_ci		   r->res_nodeid,
34562306a36Sopenharmony_ci		   r->res_master_nodeid,
34662306a36Sopenharmony_ci		   r->res_dir_nodeid,
34762306a36Sopenharmony_ci		   our_nodeid,
34862306a36Sopenharmony_ci		   r->res_toss_time,
34962306a36Sopenharmony_ci		   r->res_flags,
35062306a36Sopenharmony_ci		   r->res_length);
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	for (i = 0; i < r->res_length; i++) {
35362306a36Sopenharmony_ci		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))
35462306a36Sopenharmony_ci			print_name = 0;
35562306a36Sopenharmony_ci	}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	seq_puts(s, print_name ? "str " : "hex");
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	for (i = 0; i < r->res_length; i++) {
36062306a36Sopenharmony_ci		if (print_name)
36162306a36Sopenharmony_ci			seq_printf(s, "%c", r->res_name[i]);
36262306a36Sopenharmony_ci		else
36362306a36Sopenharmony_ci			seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci	seq_putc(s, '\n');
36662306a36Sopenharmony_ci	unlock_rsb(r);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_cistatic void print_format5_lock(struct seq_file *s, struct dlm_lkb *lkb)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct dlm_callback *cb;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	/* lkb_id lkb_flags mode flags sb_status sb_flags */
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	spin_lock(&lkb->lkb_cb_lock);
37662306a36Sopenharmony_ci	list_for_each_entry(cb, &lkb->lkb_callbacks, list) {
37762306a36Sopenharmony_ci		seq_printf(s, "%x %x %d %x %d %x\n",
37862306a36Sopenharmony_ci			   lkb->lkb_id,
37962306a36Sopenharmony_ci			   dlm_iflags_val(lkb),
38062306a36Sopenharmony_ci			   cb->mode,
38162306a36Sopenharmony_ci			   cb->flags,
38262306a36Sopenharmony_ci			   cb->sb_status,
38362306a36Sopenharmony_ci			   cb->sb_flags);
38462306a36Sopenharmony_ci	}
38562306a36Sopenharmony_ci	spin_unlock(&lkb->lkb_cb_lock);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_cistatic void print_format5(struct dlm_rsb *r, struct seq_file *s)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct dlm_lkb *lkb;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	lock_rsb(r);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
39562306a36Sopenharmony_ci		print_format5_lock(s, lkb);
39662306a36Sopenharmony_ci		if (seq_has_overflowed(s))
39762306a36Sopenharmony_ci			goto out;
39862306a36Sopenharmony_ci	}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
40162306a36Sopenharmony_ci		print_format5_lock(s, lkb);
40262306a36Sopenharmony_ci		if (seq_has_overflowed(s))
40362306a36Sopenharmony_ci			goto out;
40462306a36Sopenharmony_ci	}
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
40762306a36Sopenharmony_ci		print_format5_lock(s, lkb);
40862306a36Sopenharmony_ci		if (seq_has_overflowed(s))
40962306a36Sopenharmony_ci			goto out;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci out:
41262306a36Sopenharmony_ci	unlock_rsb(r);
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistruct rsbtbl_iter {
41662306a36Sopenharmony_ci	struct dlm_rsb *rsb;
41762306a36Sopenharmony_ci	unsigned bucket;
41862306a36Sopenharmony_ci	int format;
41962306a36Sopenharmony_ci	int header;
42062306a36Sopenharmony_ci};
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci/*
42362306a36Sopenharmony_ci * If the buffer is full, seq_printf can be called again, but it
42462306a36Sopenharmony_ci * does nothing.  So, the these printing routines periodically check
42562306a36Sopenharmony_ci * seq_has_overflowed to avoid wasting too much time trying to print to
42662306a36Sopenharmony_ci * a full buffer.
42762306a36Sopenharmony_ci */
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic int table_seq_show(struct seq_file *seq, void *iter_ptr)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	struct rsbtbl_iter *ri = iter_ptr;
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	switch (ri->format) {
43462306a36Sopenharmony_ci	case 1:
43562306a36Sopenharmony_ci		print_format1(ri->rsb, seq);
43662306a36Sopenharmony_ci		break;
43762306a36Sopenharmony_ci	case 2:
43862306a36Sopenharmony_ci		if (ri->header) {
43962306a36Sopenharmony_ci			seq_puts(seq, "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n");
44062306a36Sopenharmony_ci			ri->header = 0;
44162306a36Sopenharmony_ci		}
44262306a36Sopenharmony_ci		print_format2(ri->rsb, seq);
44362306a36Sopenharmony_ci		break;
44462306a36Sopenharmony_ci	case 3:
44562306a36Sopenharmony_ci		if (ri->header) {
44662306a36Sopenharmony_ci			seq_puts(seq, "version rsb 1.1 lvb 1.1 lkb 1.1\n");
44762306a36Sopenharmony_ci			ri->header = 0;
44862306a36Sopenharmony_ci		}
44962306a36Sopenharmony_ci		print_format3(ri->rsb, seq);
45062306a36Sopenharmony_ci		break;
45162306a36Sopenharmony_ci	case 4:
45262306a36Sopenharmony_ci		if (ri->header) {
45362306a36Sopenharmony_ci			seq_puts(seq, "version 4 rsb 2\n");
45462306a36Sopenharmony_ci			ri->header = 0;
45562306a36Sopenharmony_ci		}
45662306a36Sopenharmony_ci		print_format4(ri->rsb, seq);
45762306a36Sopenharmony_ci		break;
45862306a36Sopenharmony_ci	case 5:
45962306a36Sopenharmony_ci		if (ri->header) {
46062306a36Sopenharmony_ci			seq_puts(seq, "lkb_id lkb_flags mode flags sb_status sb_flags\n");
46162306a36Sopenharmony_ci			ri->header = 0;
46262306a36Sopenharmony_ci		}
46362306a36Sopenharmony_ci		print_format5(ri->rsb, seq);
46462306a36Sopenharmony_ci		break;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return 0;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic const struct seq_operations format1_seq_ops;
47162306a36Sopenharmony_cistatic const struct seq_operations format2_seq_ops;
47262306a36Sopenharmony_cistatic const struct seq_operations format3_seq_ops;
47362306a36Sopenharmony_cistatic const struct seq_operations format4_seq_ops;
47462306a36Sopenharmony_cistatic const struct seq_operations format5_seq_ops;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_cistatic void *table_seq_start(struct seq_file *seq, loff_t *pos)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct rb_root *tree;
47962306a36Sopenharmony_ci	struct rb_node *node;
48062306a36Sopenharmony_ci	struct dlm_ls *ls = seq->private;
48162306a36Sopenharmony_ci	struct rsbtbl_iter *ri;
48262306a36Sopenharmony_ci	struct dlm_rsb *r;
48362306a36Sopenharmony_ci	loff_t n = *pos;
48462306a36Sopenharmony_ci	unsigned bucket, entry;
48562306a36Sopenharmony_ci	int toss = (seq->op == &format4_seq_ops);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	bucket = n >> 32;
48862306a36Sopenharmony_ci	entry = n & ((1LL << 32) - 1);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (bucket >= ls->ls_rsbtbl_size)
49162306a36Sopenharmony_ci		return NULL;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	ri = kzalloc(sizeof(*ri), GFP_NOFS);
49462306a36Sopenharmony_ci	if (!ri)
49562306a36Sopenharmony_ci		return NULL;
49662306a36Sopenharmony_ci	if (n == 0)
49762306a36Sopenharmony_ci		ri->header = 1;
49862306a36Sopenharmony_ci	if (seq->op == &format1_seq_ops)
49962306a36Sopenharmony_ci		ri->format = 1;
50062306a36Sopenharmony_ci	if (seq->op == &format2_seq_ops)
50162306a36Sopenharmony_ci		ri->format = 2;
50262306a36Sopenharmony_ci	if (seq->op == &format3_seq_ops)
50362306a36Sopenharmony_ci		ri->format = 3;
50462306a36Sopenharmony_ci	if (seq->op == &format4_seq_ops)
50562306a36Sopenharmony_ci		ri->format = 4;
50662306a36Sopenharmony_ci	if (seq->op == &format5_seq_ops)
50762306a36Sopenharmony_ci		ri->format = 5;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[bucket].lock);
51262306a36Sopenharmony_ci	if (!RB_EMPTY_ROOT(tree)) {
51362306a36Sopenharmony_ci		for (node = rb_first(tree); node; node = rb_next(node)) {
51462306a36Sopenharmony_ci			r = rb_entry(node, struct dlm_rsb, res_hashnode);
51562306a36Sopenharmony_ci			if (!entry--) {
51662306a36Sopenharmony_ci				dlm_hold_rsb(r);
51762306a36Sopenharmony_ci				ri->rsb = r;
51862306a36Sopenharmony_ci				ri->bucket = bucket;
51962306a36Sopenharmony_ci				spin_unlock(&ls->ls_rsbtbl[bucket].lock);
52062306a36Sopenharmony_ci				return ri;
52162306a36Sopenharmony_ci			}
52262306a36Sopenharmony_ci		}
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	/*
52762306a36Sopenharmony_ci	 * move to the first rsb in the next non-empty bucket
52862306a36Sopenharmony_ci	 */
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	/* zero the entry */
53162306a36Sopenharmony_ci	n &= ~((1LL << 32) - 1);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	while (1) {
53462306a36Sopenharmony_ci		bucket++;
53562306a36Sopenharmony_ci		n += 1LL << 32;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		if (bucket >= ls->ls_rsbtbl_size) {
53862306a36Sopenharmony_ci			kfree(ri);
53962306a36Sopenharmony_ci			return NULL;
54062306a36Sopenharmony_ci		}
54162306a36Sopenharmony_ci		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		spin_lock(&ls->ls_rsbtbl[bucket].lock);
54462306a36Sopenharmony_ci		if (!RB_EMPTY_ROOT(tree)) {
54562306a36Sopenharmony_ci			node = rb_first(tree);
54662306a36Sopenharmony_ci			r = rb_entry(node, struct dlm_rsb, res_hashnode);
54762306a36Sopenharmony_ci			dlm_hold_rsb(r);
54862306a36Sopenharmony_ci			ri->rsb = r;
54962306a36Sopenharmony_ci			ri->bucket = bucket;
55062306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[bucket].lock);
55162306a36Sopenharmony_ci			*pos = n;
55262306a36Sopenharmony_ci			return ri;
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct dlm_ls *ls = seq->private;
56162306a36Sopenharmony_ci	struct rsbtbl_iter *ri = iter_ptr;
56262306a36Sopenharmony_ci	struct rb_root *tree;
56362306a36Sopenharmony_ci	struct rb_node *next;
56462306a36Sopenharmony_ci	struct dlm_rsb *r, *rp;
56562306a36Sopenharmony_ci	loff_t n = *pos;
56662306a36Sopenharmony_ci	unsigned bucket;
56762306a36Sopenharmony_ci	int toss = (seq->op == &format4_seq_ops);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	bucket = n >> 32;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/*
57262306a36Sopenharmony_ci	 * move to the next rsb in the same bucket
57362306a36Sopenharmony_ci	 */
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	spin_lock(&ls->ls_rsbtbl[bucket].lock);
57662306a36Sopenharmony_ci	rp = ri->rsb;
57762306a36Sopenharmony_ci	next = rb_next(&rp->res_hashnode);
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	if (next) {
58062306a36Sopenharmony_ci		r = rb_entry(next, struct dlm_rsb, res_hashnode);
58162306a36Sopenharmony_ci		dlm_hold_rsb(r);
58262306a36Sopenharmony_ci		ri->rsb = r;
58362306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
58462306a36Sopenharmony_ci		dlm_put_rsb(rp);
58562306a36Sopenharmony_ci		++*pos;
58662306a36Sopenharmony_ci		return ri;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
58962306a36Sopenharmony_ci	dlm_put_rsb(rp);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	/*
59262306a36Sopenharmony_ci	 * move to the first rsb in the next non-empty bucket
59362306a36Sopenharmony_ci	 */
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	/* zero the entry */
59662306a36Sopenharmony_ci	n &= ~((1LL << 32) - 1);
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	while (1) {
59962306a36Sopenharmony_ci		bucket++;
60062306a36Sopenharmony_ci		n += 1LL << 32;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci		if (bucket >= ls->ls_rsbtbl_size) {
60362306a36Sopenharmony_ci			kfree(ri);
60462306a36Sopenharmony_ci			++*pos;
60562306a36Sopenharmony_ci			return NULL;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		spin_lock(&ls->ls_rsbtbl[bucket].lock);
61062306a36Sopenharmony_ci		if (!RB_EMPTY_ROOT(tree)) {
61162306a36Sopenharmony_ci			next = rb_first(tree);
61262306a36Sopenharmony_ci			r = rb_entry(next, struct dlm_rsb, res_hashnode);
61362306a36Sopenharmony_ci			dlm_hold_rsb(r);
61462306a36Sopenharmony_ci			ri->rsb = r;
61562306a36Sopenharmony_ci			ri->bucket = bucket;
61662306a36Sopenharmony_ci			spin_unlock(&ls->ls_rsbtbl[bucket].lock);
61762306a36Sopenharmony_ci			*pos = n;
61862306a36Sopenharmony_ci			return ri;
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
62162306a36Sopenharmony_ci	}
62262306a36Sopenharmony_ci}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_cistatic void table_seq_stop(struct seq_file *seq, void *iter_ptr)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	struct rsbtbl_iter *ri = iter_ptr;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (ri) {
62962306a36Sopenharmony_ci		dlm_put_rsb(ri->rsb);
63062306a36Sopenharmony_ci		kfree(ri);
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_cistatic const struct seq_operations format1_seq_ops = {
63562306a36Sopenharmony_ci	.start = table_seq_start,
63662306a36Sopenharmony_ci	.next  = table_seq_next,
63762306a36Sopenharmony_ci	.stop  = table_seq_stop,
63862306a36Sopenharmony_ci	.show  = table_seq_show,
63962306a36Sopenharmony_ci};
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cistatic const struct seq_operations format2_seq_ops = {
64262306a36Sopenharmony_ci	.start = table_seq_start,
64362306a36Sopenharmony_ci	.next  = table_seq_next,
64462306a36Sopenharmony_ci	.stop  = table_seq_stop,
64562306a36Sopenharmony_ci	.show  = table_seq_show,
64662306a36Sopenharmony_ci};
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic const struct seq_operations format3_seq_ops = {
64962306a36Sopenharmony_ci	.start = table_seq_start,
65062306a36Sopenharmony_ci	.next  = table_seq_next,
65162306a36Sopenharmony_ci	.stop  = table_seq_stop,
65262306a36Sopenharmony_ci	.show  = table_seq_show,
65362306a36Sopenharmony_ci};
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic const struct seq_operations format4_seq_ops = {
65662306a36Sopenharmony_ci	.start = table_seq_start,
65762306a36Sopenharmony_ci	.next  = table_seq_next,
65862306a36Sopenharmony_ci	.stop  = table_seq_stop,
65962306a36Sopenharmony_ci	.show  = table_seq_show,
66062306a36Sopenharmony_ci};
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_cistatic const struct seq_operations format5_seq_ops = {
66362306a36Sopenharmony_ci	.start = table_seq_start,
66462306a36Sopenharmony_ci	.next  = table_seq_next,
66562306a36Sopenharmony_ci	.stop  = table_seq_stop,
66662306a36Sopenharmony_ci	.show  = table_seq_show,
66762306a36Sopenharmony_ci};
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_cistatic const struct file_operations format1_fops;
67062306a36Sopenharmony_cistatic const struct file_operations format2_fops;
67162306a36Sopenharmony_cistatic const struct file_operations format3_fops;
67262306a36Sopenharmony_cistatic const struct file_operations format4_fops;
67362306a36Sopenharmony_cistatic const struct file_operations format5_fops;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_cistatic int table_open1(struct inode *inode, struct file *file)
67662306a36Sopenharmony_ci{
67762306a36Sopenharmony_ci	struct seq_file *seq;
67862306a36Sopenharmony_ci	int ret;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	ret = seq_open(file, &format1_seq_ops);
68162306a36Sopenharmony_ci	if (ret)
68262306a36Sopenharmony_ci		return ret;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	seq = file->private_data;
68562306a36Sopenharmony_ci	seq->private = inode->i_private; /* the dlm_ls */
68662306a36Sopenharmony_ci	return 0;
68762306a36Sopenharmony_ci}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_cistatic int table_open2(struct inode *inode, struct file *file)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	struct seq_file *seq;
69262306a36Sopenharmony_ci	int ret;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	ret = seq_open(file, &format2_seq_ops);
69562306a36Sopenharmony_ci	if (ret)
69662306a36Sopenharmony_ci		return ret;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	seq = file->private_data;
69962306a36Sopenharmony_ci	seq->private = inode->i_private; /* the dlm_ls */
70062306a36Sopenharmony_ci	return 0;
70162306a36Sopenharmony_ci}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_cistatic ssize_t table_write2(struct file *file, const char __user *user_buf,
70462306a36Sopenharmony_ci			    size_t count, loff_t *ppos)
70562306a36Sopenharmony_ci{
70662306a36Sopenharmony_ci	struct seq_file *seq = file->private_data;
70762306a36Sopenharmony_ci	int n, len, lkb_nodeid, lkb_status, error;
70862306a36Sopenharmony_ci	char name[DLM_RESNAME_MAXLEN + 1] = {};
70962306a36Sopenharmony_ci	struct dlm_ls *ls = seq->private;
71062306a36Sopenharmony_ci	unsigned int lkb_flags;
71162306a36Sopenharmony_ci	char buf[256] = {};
71262306a36Sopenharmony_ci	uint32_t lkb_id;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf,
71562306a36Sopenharmony_ci			   min_t(size_t, sizeof(buf) - 1, count)))
71662306a36Sopenharmony_ci		return -EFAULT;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	n = sscanf(buf, "%x %" __stringify(DLM_RESNAME_MAXLEN) "s %x %d %d",
71962306a36Sopenharmony_ci		   &lkb_id, name, &lkb_flags, &lkb_nodeid, &lkb_status);
72062306a36Sopenharmony_ci	if (n != 5)
72162306a36Sopenharmony_ci		return -EINVAL;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	len = strnlen(name, DLM_RESNAME_MAXLEN);
72462306a36Sopenharmony_ci	error = dlm_debug_add_lkb(ls, lkb_id, name, len, lkb_flags,
72562306a36Sopenharmony_ci				  lkb_nodeid, lkb_status);
72662306a36Sopenharmony_ci	if (error)
72762306a36Sopenharmony_ci		return error;
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	return count;
73062306a36Sopenharmony_ci}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_cistatic int table_open3(struct inode *inode, struct file *file)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	struct seq_file *seq;
73562306a36Sopenharmony_ci	int ret;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	ret = seq_open(file, &format3_seq_ops);
73862306a36Sopenharmony_ci	if (ret)
73962306a36Sopenharmony_ci		return ret;
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	seq = file->private_data;
74262306a36Sopenharmony_ci	seq->private = inode->i_private; /* the dlm_ls */
74362306a36Sopenharmony_ci	return 0;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic int table_open4(struct inode *inode, struct file *file)
74762306a36Sopenharmony_ci{
74862306a36Sopenharmony_ci	struct seq_file *seq;
74962306a36Sopenharmony_ci	int ret;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	ret = seq_open(file, &format4_seq_ops);
75262306a36Sopenharmony_ci	if (ret)
75362306a36Sopenharmony_ci		return ret;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	seq = file->private_data;
75662306a36Sopenharmony_ci	seq->private = inode->i_private; /* the dlm_ls */
75762306a36Sopenharmony_ci	return 0;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic int table_open5(struct inode *inode, struct file *file)
76162306a36Sopenharmony_ci{
76262306a36Sopenharmony_ci	struct seq_file *seq;
76362306a36Sopenharmony_ci	int ret;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	ret = seq_open(file, &format5_seq_ops);
76662306a36Sopenharmony_ci	if (ret)
76762306a36Sopenharmony_ci		return ret;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	seq = file->private_data;
77062306a36Sopenharmony_ci	seq->private = inode->i_private; /* the dlm_ls */
77162306a36Sopenharmony_ci	return 0;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic const struct file_operations format1_fops = {
77562306a36Sopenharmony_ci	.owner   = THIS_MODULE,
77662306a36Sopenharmony_ci	.open    = table_open1,
77762306a36Sopenharmony_ci	.read    = seq_read,
77862306a36Sopenharmony_ci	.llseek  = seq_lseek,
77962306a36Sopenharmony_ci	.release = seq_release
78062306a36Sopenharmony_ci};
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_cistatic const struct file_operations format2_fops = {
78362306a36Sopenharmony_ci	.owner   = THIS_MODULE,
78462306a36Sopenharmony_ci	.open    = table_open2,
78562306a36Sopenharmony_ci	.read    = seq_read,
78662306a36Sopenharmony_ci	.write   = table_write2,
78762306a36Sopenharmony_ci	.llseek  = seq_lseek,
78862306a36Sopenharmony_ci	.release = seq_release
78962306a36Sopenharmony_ci};
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_cistatic const struct file_operations format3_fops = {
79262306a36Sopenharmony_ci	.owner   = THIS_MODULE,
79362306a36Sopenharmony_ci	.open    = table_open3,
79462306a36Sopenharmony_ci	.read    = seq_read,
79562306a36Sopenharmony_ci	.llseek  = seq_lseek,
79662306a36Sopenharmony_ci	.release = seq_release
79762306a36Sopenharmony_ci};
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic const struct file_operations format4_fops = {
80062306a36Sopenharmony_ci	.owner   = THIS_MODULE,
80162306a36Sopenharmony_ci	.open    = table_open4,
80262306a36Sopenharmony_ci	.read    = seq_read,
80362306a36Sopenharmony_ci	.llseek  = seq_lseek,
80462306a36Sopenharmony_ci	.release = seq_release
80562306a36Sopenharmony_ci};
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_cistatic const struct file_operations format5_fops = {
80862306a36Sopenharmony_ci	.owner   = THIS_MODULE,
80962306a36Sopenharmony_ci	.open    = table_open5,
81062306a36Sopenharmony_ci	.read    = seq_read,
81162306a36Sopenharmony_ci	.llseek  = seq_lseek,
81262306a36Sopenharmony_ci	.release = seq_release
81362306a36Sopenharmony_ci};
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci/*
81662306a36Sopenharmony_ci * dump lkb's on the ls_waiters list
81762306a36Sopenharmony_ci */
81862306a36Sopenharmony_cistatic ssize_t waiters_read(struct file *file, char __user *userbuf,
81962306a36Sopenharmony_ci			    size_t count, loff_t *ppos)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	struct dlm_ls *ls = file->private_data;
82262306a36Sopenharmony_ci	struct dlm_lkb *lkb;
82362306a36Sopenharmony_ci	size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	mutex_lock(&debug_buf_lock);
82662306a36Sopenharmony_ci	mutex_lock(&ls->ls_waiters_mutex);
82762306a36Sopenharmony_ci	memset(debug_buf, 0, sizeof(debug_buf));
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
83062306a36Sopenharmony_ci		ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
83162306a36Sopenharmony_ci			       lkb->lkb_id, lkb->lkb_wait_type,
83262306a36Sopenharmony_ci			       lkb->lkb_nodeid, lkb->lkb_resource->res_name);
83362306a36Sopenharmony_ci		if (ret >= len - pos)
83462306a36Sopenharmony_ci			break;
83562306a36Sopenharmony_ci		pos += ret;
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci	mutex_unlock(&ls->ls_waiters_mutex);
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
84062306a36Sopenharmony_ci	mutex_unlock(&debug_buf_lock);
84162306a36Sopenharmony_ci	return rv;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_cistatic ssize_t waiters_write(struct file *file, const char __user *user_buf,
84562306a36Sopenharmony_ci			     size_t count, loff_t *ppos)
84662306a36Sopenharmony_ci{
84762306a36Sopenharmony_ci	struct dlm_ls *ls = file->private_data;
84862306a36Sopenharmony_ci	int mstype, to_nodeid;
84962306a36Sopenharmony_ci	char buf[128] = {};
85062306a36Sopenharmony_ci	uint32_t lkb_id;
85162306a36Sopenharmony_ci	int n, error;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf,
85462306a36Sopenharmony_ci			   min_t(size_t, sizeof(buf) - 1, count)))
85562306a36Sopenharmony_ci		return -EFAULT;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	n = sscanf(buf, "%x %d %d", &lkb_id, &mstype, &to_nodeid);
85862306a36Sopenharmony_ci	if (n != 3)
85962306a36Sopenharmony_ci		return -EINVAL;
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	error = dlm_debug_add_lkb_to_waiters(ls, lkb_id, mstype, to_nodeid);
86262306a36Sopenharmony_ci	if (error)
86362306a36Sopenharmony_ci		return error;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	return count;
86662306a36Sopenharmony_ci}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_cistatic const struct file_operations waiters_fops = {
86962306a36Sopenharmony_ci	.owner   = THIS_MODULE,
87062306a36Sopenharmony_ci	.open    = simple_open,
87162306a36Sopenharmony_ci	.read    = waiters_read,
87262306a36Sopenharmony_ci	.write   = waiters_write,
87362306a36Sopenharmony_ci	.llseek  = default_llseek,
87462306a36Sopenharmony_ci};
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_civoid dlm_delete_debug_file(struct dlm_ls *ls)
87762306a36Sopenharmony_ci{
87862306a36Sopenharmony_ci	debugfs_remove(ls->ls_debug_rsb_dentry);
87962306a36Sopenharmony_ci	debugfs_remove(ls->ls_debug_waiters_dentry);
88062306a36Sopenharmony_ci	debugfs_remove(ls->ls_debug_locks_dentry);
88162306a36Sopenharmony_ci	debugfs_remove(ls->ls_debug_all_dentry);
88262306a36Sopenharmony_ci	debugfs_remove(ls->ls_debug_toss_dentry);
88362306a36Sopenharmony_ci	debugfs_remove(ls->ls_debug_queued_asts_dentry);
88462306a36Sopenharmony_ci}
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_cistatic int dlm_state_show(struct seq_file *file, void *offset)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	seq_printf(file, "%s\n", dlm_midcomms_state(file->private));
88962306a36Sopenharmony_ci	return 0;
89062306a36Sopenharmony_ci}
89162306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dlm_state);
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic int dlm_flags_show(struct seq_file *file, void *offset)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	seq_printf(file, "%lu\n", dlm_midcomms_flags(file->private));
89662306a36Sopenharmony_ci	return 0;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dlm_flags);
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int dlm_send_queue_cnt_show(struct seq_file *file, void *offset)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	seq_printf(file, "%d\n", dlm_midcomms_send_queue_cnt(file->private));
90362306a36Sopenharmony_ci	return 0;
90462306a36Sopenharmony_ci}
90562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dlm_send_queue_cnt);
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int dlm_version_show(struct seq_file *file, void *offset)
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	seq_printf(file, "0x%08x\n", dlm_midcomms_version(file->private));
91062306a36Sopenharmony_ci	return 0;
91162306a36Sopenharmony_ci}
91262306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(dlm_version);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_cistatic ssize_t dlm_rawmsg_write(struct file *fp, const char __user *user_buf,
91562306a36Sopenharmony_ci				size_t count, loff_t *ppos)
91662306a36Sopenharmony_ci{
91762306a36Sopenharmony_ci	void *buf;
91862306a36Sopenharmony_ci	int ret;
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci	if (count > PAGE_SIZE || count < sizeof(struct dlm_header))
92162306a36Sopenharmony_ci		return -EINVAL;
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	buf = kmalloc(PAGE_SIZE, GFP_NOFS);
92462306a36Sopenharmony_ci	if (!buf)
92562306a36Sopenharmony_ci		return -ENOMEM;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	if (copy_from_user(buf, user_buf, count)) {
92862306a36Sopenharmony_ci		ret = -EFAULT;
92962306a36Sopenharmony_ci		goto out;
93062306a36Sopenharmony_ci	}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	ret = dlm_midcomms_rawmsg_send(fp->private_data, buf, count);
93362306a36Sopenharmony_ci	if (ret)
93462306a36Sopenharmony_ci		goto out;
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci	kfree(buf);
93762306a36Sopenharmony_ci	return count;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ciout:
94062306a36Sopenharmony_ci	kfree(buf);
94162306a36Sopenharmony_ci	return ret;
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic const struct file_operations dlm_rawmsg_fops = {
94562306a36Sopenharmony_ci	.open	= simple_open,
94662306a36Sopenharmony_ci	.write	= dlm_rawmsg_write,
94762306a36Sopenharmony_ci	.llseek	= no_llseek,
94862306a36Sopenharmony_ci};
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_civoid *dlm_create_debug_comms_file(int nodeid, void *data)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	struct dentry *d_node;
95362306a36Sopenharmony_ci	char name[256];
95462306a36Sopenharmony_ci
95562306a36Sopenharmony_ci	memset(name, 0, sizeof(name));
95662306a36Sopenharmony_ci	snprintf(name, 256, "%d", nodeid);
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	d_node = debugfs_create_dir(name, dlm_comms);
95962306a36Sopenharmony_ci	debugfs_create_file("state", 0444, d_node, data, &dlm_state_fops);
96062306a36Sopenharmony_ci	debugfs_create_file("flags", 0444, d_node, data, &dlm_flags_fops);
96162306a36Sopenharmony_ci	debugfs_create_file("send_queue_count", 0444, d_node, data,
96262306a36Sopenharmony_ci			    &dlm_send_queue_cnt_fops);
96362306a36Sopenharmony_ci	debugfs_create_file("version", 0444, d_node, data, &dlm_version_fops);
96462306a36Sopenharmony_ci	debugfs_create_file("rawmsg", 0200, d_node, data, &dlm_rawmsg_fops);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	return d_node;
96762306a36Sopenharmony_ci}
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_civoid dlm_delete_debug_comms_file(void *ctx)
97062306a36Sopenharmony_ci{
97162306a36Sopenharmony_ci	debugfs_remove(ctx);
97262306a36Sopenharmony_ci}
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_civoid dlm_create_debug_file(struct dlm_ls *ls)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	/* Reserve enough space for the longest file name */
97762306a36Sopenharmony_ci	char name[DLM_LOCKSPACE_LEN + sizeof("_queued_asts")];
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	/* format 1 */
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
98262306a36Sopenharmony_ci						      S_IFREG | S_IRUGO,
98362306a36Sopenharmony_ci						      dlm_root,
98462306a36Sopenharmony_ci						      ls,
98562306a36Sopenharmony_ci						      &format1_fops);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	/* format 2 */
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	memset(name, 0, sizeof(name));
99062306a36Sopenharmony_ci	snprintf(name, sizeof(name), "%s_locks", ls->ls_name);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	ls->ls_debug_locks_dentry = debugfs_create_file(name,
99362306a36Sopenharmony_ci							0644,
99462306a36Sopenharmony_ci							dlm_root,
99562306a36Sopenharmony_ci							ls,
99662306a36Sopenharmony_ci							&format2_fops);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	/* format 3 */
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	memset(name, 0, sizeof(name));
100162306a36Sopenharmony_ci	snprintf(name, sizeof(name), "%s_all", ls->ls_name);
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	ls->ls_debug_all_dentry = debugfs_create_file(name,
100462306a36Sopenharmony_ci						      S_IFREG | S_IRUGO,
100562306a36Sopenharmony_ci						      dlm_root,
100662306a36Sopenharmony_ci						      ls,
100762306a36Sopenharmony_ci						      &format3_fops);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	/* format 4 */
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	memset(name, 0, sizeof(name));
101262306a36Sopenharmony_ci	snprintf(name, sizeof(name), "%s_toss", ls->ls_name);
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	ls->ls_debug_toss_dentry = debugfs_create_file(name,
101562306a36Sopenharmony_ci						       S_IFREG | S_IRUGO,
101662306a36Sopenharmony_ci						       dlm_root,
101762306a36Sopenharmony_ci						       ls,
101862306a36Sopenharmony_ci						       &format4_fops);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	memset(name, 0, sizeof(name));
102162306a36Sopenharmony_ci	snprintf(name, sizeof(name), "%s_waiters", ls->ls_name);
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	ls->ls_debug_waiters_dentry = debugfs_create_file(name,
102462306a36Sopenharmony_ci							  0644,
102562306a36Sopenharmony_ci							  dlm_root,
102662306a36Sopenharmony_ci							  ls,
102762306a36Sopenharmony_ci							  &waiters_fops);
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	/* format 5 */
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	memset(name, 0, sizeof(name));
103262306a36Sopenharmony_ci	snprintf(name, sizeof(name), "%s_queued_asts", ls->ls_name);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	ls->ls_debug_queued_asts_dentry = debugfs_create_file(name,
103562306a36Sopenharmony_ci							      0644,
103662306a36Sopenharmony_ci							      dlm_root,
103762306a36Sopenharmony_ci							      ls,
103862306a36Sopenharmony_ci							      &format5_fops);
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_civoid __init dlm_register_debugfs(void)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	mutex_init(&debug_buf_lock);
104462306a36Sopenharmony_ci	dlm_root = debugfs_create_dir("dlm", NULL);
104562306a36Sopenharmony_ci	dlm_comms = debugfs_create_dir("comms", dlm_root);
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_civoid dlm_unregister_debugfs(void)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	debugfs_remove(dlm_root);
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
1053