xref: /openbmc/linux/fs/dlm/debug_fs.c (revision 1188f7f111c61394ec56beb8e30322305a8220b6)
12522fe45SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2e7fd4179SDavid Teigland /******************************************************************************
3e7fd4179SDavid Teigland *******************************************************************************
4e7fd4179SDavid Teigland **
5892c4467SDavid Teigland **  Copyright (C) 2005-2009 Red Hat, Inc.  All rights reserved.
6e7fd4179SDavid Teigland **
7e7fd4179SDavid Teigland **
8e7fd4179SDavid Teigland *******************************************************************************
9e7fd4179SDavid Teigland ******************************************************************************/
10e7fd4179SDavid Teigland 
11e7fd4179SDavid Teigland #include <linux/pagemap.h>
12e7fd4179SDavid Teigland #include <linux/seq_file.h>
137963b8a5SPaul Gortmaker #include <linux/init.h>
14e7fd4179SDavid Teigland #include <linux/ctype.h>
15e7fd4179SDavid Teigland #include <linux/debugfs.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
17e7fd4179SDavid Teigland 
18e7fd4179SDavid Teigland #include "dlm_internal.h"
195b2f981fSAlexander Aring #include "midcomms.h"
20916297aaSJosef Bacik #include "lock.h"
21541adb0dSAlexander Aring #include "ast.h"
22e7fd4179SDavid Teigland 
235de6319bSDavid Teigland #define DLM_DEBUG_BUF_LEN 4096
245de6319bSDavid Teigland static char debug_buf[DLM_DEBUG_BUF_LEN];
255de6319bSDavid Teigland static struct mutex debug_buf_lock;
26e7fd4179SDavid Teigland 
27e7fd4179SDavid Teigland static struct dentry *dlm_root;
285b2f981fSAlexander Aring static struct dentry *dlm_comms;
29e7fd4179SDavid Teigland 
print_lockmode(int mode)30e7fd4179SDavid Teigland static char *print_lockmode(int mode)
31e7fd4179SDavid Teigland {
32e7fd4179SDavid Teigland 	switch (mode) {
33e7fd4179SDavid Teigland 	case DLM_LOCK_IV:
34e7fd4179SDavid Teigland 		return "--";
35e7fd4179SDavid Teigland 	case DLM_LOCK_NL:
36e7fd4179SDavid Teigland 		return "NL";
37e7fd4179SDavid Teigland 	case DLM_LOCK_CR:
38e7fd4179SDavid Teigland 		return "CR";
39e7fd4179SDavid Teigland 	case DLM_LOCK_CW:
40e7fd4179SDavid Teigland 		return "CW";
41e7fd4179SDavid Teigland 	case DLM_LOCK_PR:
42e7fd4179SDavid Teigland 		return "PR";
43e7fd4179SDavid Teigland 	case DLM_LOCK_PW:
44e7fd4179SDavid Teigland 		return "PW";
45e7fd4179SDavid Teigland 	case DLM_LOCK_EX:
46e7fd4179SDavid Teigland 		return "EX";
47e7fd4179SDavid Teigland 	default:
48e7fd4179SDavid Teigland 		return "??";
49e7fd4179SDavid Teigland 	}
50e7fd4179SDavid Teigland }
51e7fd4179SDavid Teigland 
print_format1_lock(struct seq_file * s,struct dlm_lkb * lkb,struct dlm_rsb * res)52d6d906b2SJoe Perches static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,
53e7fd4179SDavid Teigland 			       struct dlm_rsb *res)
54e7fd4179SDavid Teigland {
55e7fd4179SDavid Teigland 	seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
56e7fd4179SDavid Teigland 
57892c4467SDavid Teigland 	if (lkb->lkb_status == DLM_LKSTS_CONVERT ||
58892c4467SDavid Teigland 	    lkb->lkb_status == DLM_LKSTS_WAITING)
59e7fd4179SDavid Teigland 		seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
60e7fd4179SDavid Teigland 
61e7fd4179SDavid Teigland 	if (lkb->lkb_nodeid) {
62e7fd4179SDavid Teigland 		if (lkb->lkb_nodeid != res->res_nodeid)
63e7fd4179SDavid Teigland 			seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
64e7fd4179SDavid Teigland 				   lkb->lkb_remid);
65e7fd4179SDavid Teigland 		else
66e7fd4179SDavid Teigland 			seq_printf(s, " Master:     %08x", lkb->lkb_remid);
67e7fd4179SDavid Teigland 	}
68e7fd4179SDavid Teigland 
69e7fd4179SDavid Teigland 	if (lkb->lkb_wait_type)
70e7fd4179SDavid Teigland 		seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
71e7fd4179SDavid Teigland 
72653996caSMarkus Elfring 	seq_putc(s, '\n');
73e7fd4179SDavid Teigland }
74e7fd4179SDavid Teigland 
print_format1(struct dlm_rsb * res,struct seq_file * s)75d6d906b2SJoe Perches static void print_format1(struct dlm_rsb *res, struct seq_file *s)
76e7fd4179SDavid Teigland {
77e7fd4179SDavid Teigland 	struct dlm_lkb *lkb;
785de6319bSDavid Teigland 	int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
79e7fd4179SDavid Teigland 
809dd592d7SDavid Teigland 	lock_rsb(res);
819dd592d7SDavid Teigland 
82d6d906b2SJoe Perches 	seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
83892c4467SDavid Teigland 
84e7fd4179SDavid Teigland 	for (i = 0; i < res->res_length; i++) {
85e7fd4179SDavid Teigland 		if (isprint(res->res_name[i]))
86e7fd4179SDavid Teigland 			seq_printf(s, "%c", res->res_name[i]);
87e7fd4179SDavid Teigland 		else
88e7fd4179SDavid Teigland 			seq_printf(s, "%c", '.');
89e7fd4179SDavid Teigland 	}
90892c4467SDavid Teigland 
91e7fd4179SDavid Teigland 	if (res->res_nodeid > 0)
92d6d906b2SJoe Perches 		seq_printf(s, "\"\nLocal Copy, Master is node %d\n",
93e7fd4179SDavid Teigland 			   res->res_nodeid);
94e7fd4179SDavid Teigland 	else if (res->res_nodeid == 0)
95d6d906b2SJoe Perches 		seq_puts(s, "\"\nMaster Copy\n");
96e7fd4179SDavid Teigland 	else if (res->res_nodeid == -1)
97d6d906b2SJoe Perches 		seq_printf(s, "\"\nLooking up master (lkid %x)\n",
98e7fd4179SDavid Teigland 			   res->res_first_lkid);
99e7fd4179SDavid Teigland 	else
100d6d906b2SJoe Perches 		seq_printf(s, "\"\nInvalid master %d\n", res->res_nodeid);
101d6d906b2SJoe Perches 	if (seq_has_overflowed(s))
102892c4467SDavid Teigland 		goto out;
103e7fd4179SDavid Teigland 
104e7fd4179SDavid Teigland 	/* Print the LVB: */
105e7fd4179SDavid Teigland 	if (res->res_lvbptr) {
106c1d4518cSFabian Frederick 		seq_puts(s, "LVB: ");
107e7fd4179SDavid Teigland 		for (i = 0; i < lvblen; i++) {
108e7fd4179SDavid Teigland 			if (i == lvblen / 2)
109c1d4518cSFabian Frederick 				seq_puts(s, "\n     ");
110e7fd4179SDavid Teigland 			seq_printf(s, "%02x ",
111e7fd4179SDavid Teigland 				   (unsigned char) res->res_lvbptr[i]);
112e7fd4179SDavid Teigland 		}
113e7fd4179SDavid Teigland 		if (rsb_flag(res, RSB_VALNOTVALID))
114c1d4518cSFabian Frederick 			seq_puts(s, " (INVALID)");
115653996caSMarkus Elfring 		seq_putc(s, '\n');
116d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
117892c4467SDavid Teigland 			goto out;
118e7fd4179SDavid Teigland 	}
119e7fd4179SDavid Teigland 
1205de6319bSDavid Teigland 	root_list = !list_empty(&res->res_root_list);
1215de6319bSDavid Teigland 	recover_list = !list_empty(&res->res_recover_list);
1225de6319bSDavid Teigland 
1235de6319bSDavid Teigland 	if (root_list || recover_list) {
124d6d906b2SJoe Perches 		seq_printf(s, "Recovery: root %d recover %d flags %lx count %d\n",
125d6d906b2SJoe Perches 			   root_list, recover_list,
12620abf975SDavid Teigland 			   res->res_flags, res->res_recover_locks_count);
1275de6319bSDavid Teigland 	}
1285de6319bSDavid Teigland 
129e7fd4179SDavid Teigland 	/* Print the locks attached to this resource */
130c1d4518cSFabian Frederick 	seq_puts(s, "Granted Queue\n");
131892c4467SDavid Teigland 	list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) {
132d6d906b2SJoe Perches 		print_format1_lock(s, lkb, res);
133d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
134892c4467SDavid Teigland 			goto out;
135892c4467SDavid Teigland 	}
136e7fd4179SDavid Teigland 
137c1d4518cSFabian Frederick 	seq_puts(s, "Conversion Queue\n");
138892c4467SDavid Teigland 	list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) {
139d6d906b2SJoe Perches 		print_format1_lock(s, lkb, res);
140d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
141892c4467SDavid Teigland 			goto out;
142892c4467SDavid Teigland 	}
143e7fd4179SDavid Teigland 
144c1d4518cSFabian Frederick 	seq_puts(s, "Waiting Queue\n");
145892c4467SDavid Teigland 	list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) {
146d6d906b2SJoe Perches 		print_format1_lock(s, lkb, res);
147d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
148892c4467SDavid Teigland 			goto out;
149892c4467SDavid Teigland 	}
150e7fd4179SDavid Teigland 
1515de6319bSDavid Teigland 	if (list_empty(&res->res_lookup))
1525de6319bSDavid Teigland 		goto out;
1535de6319bSDavid Teigland 
154c1d4518cSFabian Frederick 	seq_puts(s, "Lookup Queue\n");
1555de6319bSDavid Teigland 	list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
156d6d906b2SJoe Perches 		seq_printf(s, "%08x %s",
157d6d906b2SJoe Perches 			   lkb->lkb_id, print_lockmode(lkb->lkb_rqmode));
1585de6319bSDavid Teigland 		if (lkb->lkb_wait_type)
1595de6319bSDavid Teigland 			seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
160653996caSMarkus Elfring 		seq_putc(s, '\n');
161d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
162d6d906b2SJoe Perches 			goto out;
1635de6319bSDavid Teigland 	}
1645de6319bSDavid Teigland  out:
1659dd592d7SDavid Teigland 	unlock_rsb(res);
1669dd592d7SDavid Teigland }
1679dd592d7SDavid Teigland 
print_format2_lock(struct seq_file * s,struct dlm_lkb * lkb,struct dlm_rsb * r)168d6d906b2SJoe Perches static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,
169d022509dSDavid Teigland 			       struct dlm_rsb *r)
1709dd592d7SDavid Teigland {
171eeda418dSDavid Teigland 	u64 xid = 0;
172eeda418dSDavid Teigland 	u64 us;
1739dd592d7SDavid Teigland 
1748a39dcd9SAlexander Aring 	if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
175d292c0ccSDavid Teigland 		if (lkb->lkb_ua)
176d292c0ccSDavid Teigland 			xid = lkb->lkb_ua->xid;
1779dd592d7SDavid Teigland 	}
1789dd592d7SDavid Teigland 
179eeda418dSDavid Teigland 	/* microseconds since lkb was added to current queue */
180eeda418dSDavid Teigland 	us = ktime_to_us(ktime_sub(ktime_get(), lkb->lkb_timestamp));
1819dd592d7SDavid Teigland 
182eeda418dSDavid Teigland 	/* id nodeid remid pid xid exflags flags sts grmode rqmode time_us
183ac90a255SDavid Teigland 	   r_nodeid r_len r_name */
1849dd592d7SDavid Teigland 
185d6d906b2SJoe Perches 	seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n",
1869dd592d7SDavid Teigland 		   lkb->lkb_id,
1879dd592d7SDavid Teigland 		   lkb->lkb_nodeid,
1889dd592d7SDavid Teigland 		   lkb->lkb_remid,
1899dd592d7SDavid Teigland 		   lkb->lkb_ownpid,
1909dd592d7SDavid Teigland 		   (unsigned long long)xid,
1919dd592d7SDavid Teigland 		   lkb->lkb_exflags,
192e1af8728SAlexander Aring 		   dlm_iflags_val(lkb),
1939dd592d7SDavid Teigland 		   lkb->lkb_status,
1949dd592d7SDavid Teigland 		   lkb->lkb_grmode,
1959dd592d7SDavid Teigland 		   lkb->lkb_rqmode,
196eeda418dSDavid Teigland 		   (unsigned long long)us,
197ac90a255SDavid Teigland 		   r->res_nodeid,
1989dd592d7SDavid Teigland 		   r->res_length,
1999dd592d7SDavid Teigland 		   r->res_name);
2009dd592d7SDavid Teigland }
2019dd592d7SDavid Teigland 
print_format2(struct dlm_rsb * r,struct seq_file * s)202d6d906b2SJoe Perches static void print_format2(struct dlm_rsb *r, struct seq_file *s)
2039dd592d7SDavid Teigland {
2049dd592d7SDavid Teigland 	struct dlm_lkb *lkb;
2059dd592d7SDavid Teigland 
2069dd592d7SDavid Teigland 	lock_rsb(r);
2079dd592d7SDavid Teigland 
208892c4467SDavid Teigland 	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
209d6d906b2SJoe Perches 		print_format2_lock(s, lkb, r);
210d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
211892c4467SDavid Teigland 			goto out;
212d022509dSDavid Teigland 	}
213d022509dSDavid Teigland 
214892c4467SDavid Teigland 	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
215d6d906b2SJoe Perches 		print_format2_lock(s, lkb, r);
216d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
217892c4467SDavid Teigland 			goto out;
218892c4467SDavid Teigland 	}
219892c4467SDavid Teigland 
220892c4467SDavid Teigland 	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
221d6d906b2SJoe Perches 		print_format2_lock(s, lkb, r);
222d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
223892c4467SDavid Teigland 			goto out;
224892c4467SDavid Teigland 	}
225892c4467SDavid Teigland  out:
226892c4467SDavid Teigland 	unlock_rsb(r);
227892c4467SDavid Teigland }
228892c4467SDavid Teigland 
print_format3_lock(struct seq_file * s,struct dlm_lkb * lkb,int rsb_lookup)229d6d906b2SJoe Perches static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
230d022509dSDavid Teigland 			      int rsb_lookup)
231d022509dSDavid Teigland {
232d022509dSDavid Teigland 	u64 xid = 0;
233d022509dSDavid Teigland 
2348a39dcd9SAlexander Aring 	if (test_bit(DLM_DFL_USER_BIT, &lkb->lkb_dflags)) {
235d022509dSDavid Teigland 		if (lkb->lkb_ua)
236d022509dSDavid Teigland 			xid = lkb->lkb_ua->xid;
237d022509dSDavid Teigland 	}
238d022509dSDavid Teigland 
239d6d906b2SJoe Perches 	seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n",
240d022509dSDavid Teigland 		   lkb->lkb_id,
241d022509dSDavid Teigland 		   lkb->lkb_nodeid,
242d022509dSDavid Teigland 		   lkb->lkb_remid,
243d022509dSDavid Teigland 		   lkb->lkb_ownpid,
244d022509dSDavid Teigland 		   (unsigned long long)xid,
245d022509dSDavid Teigland 		   lkb->lkb_exflags,
246e1af8728SAlexander Aring 		   dlm_iflags_val(lkb),
247d022509dSDavid Teigland 		   lkb->lkb_status,
248d022509dSDavid Teigland 		   lkb->lkb_grmode,
249d022509dSDavid Teigland 		   lkb->lkb_rqmode,
25061bed0baSAlexander Aring 		   lkb->lkb_last_bast_mode,
251d022509dSDavid Teigland 		   rsb_lookup,
252d022509dSDavid Teigland 		   lkb->lkb_wait_type,
253d022509dSDavid Teigland 		   lkb->lkb_lvbseq,
254d022509dSDavid Teigland 		   (unsigned long long)ktime_to_ns(lkb->lkb_timestamp),
2558304d6f2SDavid Teigland 		   (unsigned long long)ktime_to_ns(lkb->lkb_last_bast_time));
256d022509dSDavid Teigland }
257d022509dSDavid Teigland 
print_format3(struct dlm_rsb * r,struct seq_file * s)258d6d906b2SJoe Perches static void print_format3(struct dlm_rsb *r, struct seq_file *s)
259d022509dSDavid Teigland {
260d022509dSDavid Teigland 	struct dlm_lkb *lkb;
261d022509dSDavid Teigland 	int i, lvblen = r->res_ls->ls_lvblen;
262d022509dSDavid Teigland 	int print_name = 1;
263d022509dSDavid Teigland 
264d022509dSDavid Teigland 	lock_rsb(r);
265d022509dSDavid Teigland 
266d6d906b2SJoe Perches 	seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ",
267d022509dSDavid Teigland 		   r,
268d022509dSDavid Teigland 		   r->res_nodeid,
269d022509dSDavid Teigland 		   r->res_first_lkid,
270d022509dSDavid Teigland 		   r->res_flags,
271d022509dSDavid Teigland 		   !list_empty(&r->res_root_list),
272d022509dSDavid Teigland 		   !list_empty(&r->res_recover_list),
273d022509dSDavid Teigland 		   r->res_recover_locks_count,
274d022509dSDavid Teigland 		   r->res_length);
275d6d906b2SJoe Perches 	if (seq_has_overflowed(s))
276892c4467SDavid Teigland 		goto out;
277d022509dSDavid Teigland 
278d022509dSDavid Teigland 	for (i = 0; i < r->res_length; i++) {
279d022509dSDavid Teigland 		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))
280d022509dSDavid Teigland 			print_name = 0;
281d022509dSDavid Teigland 	}
282d022509dSDavid Teigland 
283f365ef9bSJoe Perches 	seq_puts(s, print_name ? "str " : "hex");
284d022509dSDavid Teigland 
285d022509dSDavid Teigland 	for (i = 0; i < r->res_length; i++) {
286d022509dSDavid Teigland 		if (print_name)
287d022509dSDavid Teigland 			seq_printf(s, "%c", r->res_name[i]);
288d022509dSDavid Teigland 		else
289d022509dSDavid Teigland 			seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
290d022509dSDavid Teigland 	}
291653996caSMarkus Elfring 	seq_putc(s, '\n');
292d6d906b2SJoe Perches 	if (seq_has_overflowed(s))
293892c4467SDavid Teigland 		goto out;
294d022509dSDavid Teigland 
295d022509dSDavid Teigland 	if (!r->res_lvbptr)
296d022509dSDavid Teigland 		goto do_locks;
297d022509dSDavid Teigland 
298d022509dSDavid Teigland 	seq_printf(s, "lvb %u %d", r->res_lvbseq, lvblen);
299d022509dSDavid Teigland 
300d022509dSDavid Teigland 	for (i = 0; i < lvblen; i++)
301d022509dSDavid Teigland 		seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]);
302653996caSMarkus Elfring 	seq_putc(s, '\n');
303d6d906b2SJoe Perches 	if (seq_has_overflowed(s))
304892c4467SDavid Teigland 		goto out;
305d022509dSDavid Teigland 
306d022509dSDavid Teigland  do_locks:
307892c4467SDavid Teigland 	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
308d6d906b2SJoe Perches 		print_format3_lock(s, lkb, 0);
309d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
310892c4467SDavid Teigland 			goto out;
311892c4467SDavid Teigland 	}
312d022509dSDavid Teigland 
313892c4467SDavid Teigland 	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
314d6d906b2SJoe Perches 		print_format3_lock(s, lkb, 0);
315d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
316892c4467SDavid Teigland 			goto out;
317892c4467SDavid Teigland 	}
318d022509dSDavid Teigland 
319892c4467SDavid Teigland 	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
320d6d906b2SJoe Perches 		print_format3_lock(s, lkb, 0);
321d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
322892c4467SDavid Teigland 			goto out;
323892c4467SDavid Teigland 	}
324d022509dSDavid Teigland 
325892c4467SDavid Teigland 	list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) {
326d6d906b2SJoe Perches 		print_format3_lock(s, lkb, 1);
327d6d906b2SJoe Perches 		if (seq_has_overflowed(s))
328892c4467SDavid Teigland 			goto out;
329892c4467SDavid Teigland 	}
330892c4467SDavid Teigland  out:
3319dd592d7SDavid Teigland 	unlock_rsb(r);
332e7fd4179SDavid Teigland }
333e7fd4179SDavid Teigland 
print_format4(struct dlm_rsb * r,struct seq_file * s)334d6d906b2SJoe Perches static void print_format4(struct dlm_rsb *r, struct seq_file *s)
335c04fecb4SDavid Teigland {
336c04fecb4SDavid Teigland 	int our_nodeid = dlm_our_nodeid();
337c04fecb4SDavid Teigland 	int print_name = 1;
338d6d906b2SJoe Perches 	int i;
339c04fecb4SDavid Teigland 
340c04fecb4SDavid Teigland 	lock_rsb(r);
341c04fecb4SDavid Teigland 
342d6d906b2SJoe Perches 	seq_printf(s, "rsb %p %d %d %d %d %lu %lx %d ",
343c04fecb4SDavid Teigland 		   r,
344c04fecb4SDavid Teigland 		   r->res_nodeid,
345c04fecb4SDavid Teigland 		   r->res_master_nodeid,
346c04fecb4SDavid Teigland 		   r->res_dir_nodeid,
347c04fecb4SDavid Teigland 		   our_nodeid,
348c04fecb4SDavid Teigland 		   r->res_toss_time,
349c04fecb4SDavid Teigland 		   r->res_flags,
350c04fecb4SDavid Teigland 		   r->res_length);
351c04fecb4SDavid Teigland 
352c04fecb4SDavid Teigland 	for (i = 0; i < r->res_length; i++) {
353c04fecb4SDavid Teigland 		if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))
354c04fecb4SDavid Teigland 			print_name = 0;
355c04fecb4SDavid Teigland 	}
356c04fecb4SDavid Teigland 
357f365ef9bSJoe Perches 	seq_puts(s, print_name ? "str " : "hex");
358c04fecb4SDavid Teigland 
359c04fecb4SDavid Teigland 	for (i = 0; i < r->res_length; i++) {
360c04fecb4SDavid Teigland 		if (print_name)
361c04fecb4SDavid Teigland 			seq_printf(s, "%c", r->res_name[i]);
362c04fecb4SDavid Teigland 		else
363c04fecb4SDavid Teigland 			seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
364c04fecb4SDavid Teigland 	}
365653996caSMarkus Elfring 	seq_putc(s, '\n');
366c04fecb4SDavid Teigland 	unlock_rsb(r);
367c04fecb4SDavid Teigland }
368c04fecb4SDavid Teigland 
print_format5_lock(struct seq_file * s,struct dlm_lkb * lkb)369541adb0dSAlexander Aring static void print_format5_lock(struct seq_file *s, struct dlm_lkb *lkb)
370541adb0dSAlexander Aring {
371541adb0dSAlexander Aring 	struct dlm_callback *cb;
372541adb0dSAlexander Aring 
373541adb0dSAlexander Aring 	/* lkb_id lkb_flags mode flags sb_status sb_flags */
374541adb0dSAlexander Aring 
375541adb0dSAlexander Aring 	spin_lock(&lkb->lkb_cb_lock);
376541adb0dSAlexander Aring 	list_for_each_entry(cb, &lkb->lkb_callbacks, list) {
377541adb0dSAlexander Aring 		seq_printf(s, "%x %x %d %x %d %x\n",
378541adb0dSAlexander Aring 			   lkb->lkb_id,
379541adb0dSAlexander Aring 			   dlm_iflags_val(lkb),
380541adb0dSAlexander Aring 			   cb->mode,
381541adb0dSAlexander Aring 			   cb->flags,
382541adb0dSAlexander Aring 			   cb->sb_status,
383541adb0dSAlexander Aring 			   cb->sb_flags);
384541adb0dSAlexander Aring 	}
385541adb0dSAlexander Aring 	spin_unlock(&lkb->lkb_cb_lock);
386541adb0dSAlexander Aring }
387541adb0dSAlexander Aring 
print_format5(struct dlm_rsb * r,struct seq_file * s)388541adb0dSAlexander Aring static void print_format5(struct dlm_rsb *r, struct seq_file *s)
389541adb0dSAlexander Aring {
390541adb0dSAlexander Aring 	struct dlm_lkb *lkb;
391541adb0dSAlexander Aring 
392541adb0dSAlexander Aring 	lock_rsb(r);
393541adb0dSAlexander Aring 
394541adb0dSAlexander Aring 	list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
395541adb0dSAlexander Aring 		print_format5_lock(s, lkb);
396541adb0dSAlexander Aring 		if (seq_has_overflowed(s))
397541adb0dSAlexander Aring 			goto out;
398541adb0dSAlexander Aring 	}
399541adb0dSAlexander Aring 
400541adb0dSAlexander Aring 	list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
401541adb0dSAlexander Aring 		print_format5_lock(s, lkb);
402541adb0dSAlexander Aring 		if (seq_has_overflowed(s))
403541adb0dSAlexander Aring 			goto out;
404541adb0dSAlexander Aring 	}
405541adb0dSAlexander Aring 
406541adb0dSAlexander Aring 	list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
407541adb0dSAlexander Aring 		print_format5_lock(s, lkb);
408541adb0dSAlexander Aring 		if (seq_has_overflowed(s))
409541adb0dSAlexander Aring 			goto out;
410541adb0dSAlexander Aring 	}
411541adb0dSAlexander Aring  out:
412541adb0dSAlexander Aring 	unlock_rsb(r);
413541adb0dSAlexander Aring }
414541adb0dSAlexander Aring 
415892c4467SDavid Teigland struct rsbtbl_iter {
416892c4467SDavid Teigland 	struct dlm_rsb *rsb;
417892c4467SDavid Teigland 	unsigned bucket;
418892c4467SDavid Teigland 	int format;
419892c4467SDavid Teigland 	int header;
420892c4467SDavid Teigland };
421892c4467SDavid Teigland 
422d6d906b2SJoe Perches /*
423d6d906b2SJoe Perches  * If the buffer is full, seq_printf can be called again, but it
424d6d906b2SJoe Perches  * does nothing.  So, the these printing routines periodically check
425d6d906b2SJoe Perches  * seq_has_overflowed to avoid wasting too much time trying to print to
426d6d906b2SJoe Perches  * a full buffer.
427d6d906b2SJoe Perches  */
428892c4467SDavid Teigland 
table_seq_show(struct seq_file * seq,void * iter_ptr)429892c4467SDavid Teigland static int table_seq_show(struct seq_file *seq, void *iter_ptr)
430e7fd4179SDavid Teigland {
431892c4467SDavid Teigland 	struct rsbtbl_iter *ri = iter_ptr;
432e7fd4179SDavid Teigland 
433d022509dSDavid Teigland 	switch (ri->format) {
434d022509dSDavid Teigland 	case 1:
435d6d906b2SJoe Perches 		print_format1(ri->rsb, seq);
436d022509dSDavid Teigland 		break;
437d022509dSDavid Teigland 	case 2:
4389dd592d7SDavid Teigland 		if (ri->header) {
439f365ef9bSJoe Perches 			seq_puts(seq, "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n");
4409dd592d7SDavid Teigland 			ri->header = 0;
4419dd592d7SDavid Teigland 		}
442d6d906b2SJoe Perches 		print_format2(ri->rsb, seq);
443d022509dSDavid Teigland 		break;
444d022509dSDavid Teigland 	case 3:
445d022509dSDavid Teigland 		if (ri->header) {
446f365ef9bSJoe Perches 			seq_puts(seq, "version rsb 1.1 lvb 1.1 lkb 1.1\n");
447d022509dSDavid Teigland 			ri->header = 0;
448d022509dSDavid Teigland 		}
449d6d906b2SJoe Perches 		print_format3(ri->rsb, seq);
450d022509dSDavid Teigland 		break;
451c04fecb4SDavid Teigland 	case 4:
452c04fecb4SDavid Teigland 		if (ri->header) {
453f365ef9bSJoe Perches 			seq_puts(seq, "version 4 rsb 2\n");
454c04fecb4SDavid Teigland 			ri->header = 0;
455c04fecb4SDavid Teigland 		}
456d6d906b2SJoe Perches 		print_format4(ri->rsb, seq);
457c04fecb4SDavid Teigland 		break;
458541adb0dSAlexander Aring 	case 5:
459541adb0dSAlexander Aring 		if (ri->header) {
460541adb0dSAlexander Aring 			seq_puts(seq, "lkb_id lkb_flags mode flags sb_status sb_flags\n");
461541adb0dSAlexander Aring 			ri->header = 0;
462541adb0dSAlexander Aring 		}
463541adb0dSAlexander Aring 		print_format5(ri->rsb, seq);
464541adb0dSAlexander Aring 		break;
4659dd592d7SDavid Teigland 	}
466e7fd4179SDavid Teigland 
467d6d906b2SJoe Perches 	return 0;
468e7fd4179SDavid Teigland }
469e7fd4179SDavid Teigland 
47088e9d34cSJames Morris static const struct seq_operations format1_seq_ops;
47188e9d34cSJames Morris static const struct seq_operations format2_seq_ops;
47288e9d34cSJames Morris static const struct seq_operations format3_seq_ops;
473c04fecb4SDavid Teigland static const struct seq_operations format4_seq_ops;
474541adb0dSAlexander Aring static const struct seq_operations format5_seq_ops;
475e7fd4179SDavid Teigland 
table_seq_start(struct seq_file * seq,loff_t * pos)476892c4467SDavid Teigland static void *table_seq_start(struct seq_file *seq, loff_t *pos)
477e7fd4179SDavid Teigland {
478c04fecb4SDavid Teigland 	struct rb_root *tree;
4799beb3bf5SBob Peterson 	struct rb_node *node;
480892c4467SDavid Teigland 	struct dlm_ls *ls = seq->private;
481892c4467SDavid Teigland 	struct rsbtbl_iter *ri;
482892c4467SDavid Teigland 	struct dlm_rsb *r;
4839dd592d7SDavid Teigland 	loff_t n = *pos;
484892c4467SDavid Teigland 	unsigned bucket, entry;
485c04fecb4SDavid Teigland 	int toss = (seq->op == &format4_seq_ops);
4869dd592d7SDavid Teigland 
487892c4467SDavid Teigland 	bucket = n >> 32;
488892c4467SDavid Teigland 	entry = n & ((1LL << 32) - 1);
489892c4467SDavid Teigland 
490892c4467SDavid Teigland 	if (bucket >= ls->ls_rsbtbl_size)
491892c4467SDavid Teigland 		return NULL;
492892c4467SDavid Teigland 
4932c257e96SMarkus Elfring 	ri = kzalloc(sizeof(*ri), GFP_NOFS);
4949dd592d7SDavid Teigland 	if (!ri)
4959dd592d7SDavid Teigland 		return NULL;
496892c4467SDavid Teigland 	if (n == 0)
497892c4467SDavid Teigland 		ri->header = 1;
498892c4467SDavid Teigland 	if (seq->op == &format1_seq_ops)
499892c4467SDavid Teigland 		ri->format = 1;
500892c4467SDavid Teigland 	if (seq->op == &format2_seq_ops)
501892c4467SDavid Teigland 		ri->format = 2;
502892c4467SDavid Teigland 	if (seq->op == &format3_seq_ops)
503d022509dSDavid Teigland 		ri->format = 3;
504c04fecb4SDavid Teigland 	if (seq->op == &format4_seq_ops)
505c04fecb4SDavid Teigland 		ri->format = 4;
506541adb0dSAlexander Aring 	if (seq->op == &format5_seq_ops)
507541adb0dSAlexander Aring 		ri->format = 5;
508c04fecb4SDavid Teigland 
509c04fecb4SDavid Teigland 	tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
510d022509dSDavid Teigland 
511c7be761aSDavid Teigland 	spin_lock(&ls->ls_rsbtbl[bucket].lock);
512c04fecb4SDavid Teigland 	if (!RB_EMPTY_ROOT(tree)) {
513c04fecb4SDavid Teigland 		for (node = rb_first(tree); node; node = rb_next(node)) {
5149beb3bf5SBob Peterson 			r = rb_entry(node, struct dlm_rsb, res_hashnode);
515892c4467SDavid Teigland 			if (!entry--) {
516892c4467SDavid Teigland 				dlm_hold_rsb(r);
517892c4467SDavid Teigland 				ri->rsb = r;
518892c4467SDavid Teigland 				ri->bucket = bucket;
519c7be761aSDavid Teigland 				spin_unlock(&ls->ls_rsbtbl[bucket].lock);
520892c4467SDavid Teigland 				return ri;
521892c4467SDavid Teigland 			}
522892c4467SDavid Teigland 		}
523892c4467SDavid Teigland 	}
524c7be761aSDavid Teigland 	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
525d022509dSDavid Teigland 
526892c4467SDavid Teigland 	/*
527892c4467SDavid Teigland 	 * move to the first rsb in the next non-empty bucket
528892c4467SDavid Teigland 	 */
529892c4467SDavid Teigland 
530892c4467SDavid Teigland 	/* zero the entry */
531892c4467SDavid Teigland 	n &= ~((1LL << 32) - 1);
532892c4467SDavid Teigland 
533892c4467SDavid Teigland 	while (1) {
534892c4467SDavid Teigland 		bucket++;
535892c4467SDavid Teigland 		n += 1LL << 32;
536892c4467SDavid Teigland 
537892c4467SDavid Teigland 		if (bucket >= ls->ls_rsbtbl_size) {
538892c4467SDavid Teigland 			kfree(ri);
539d022509dSDavid Teigland 			return NULL;
540d022509dSDavid Teigland 		}
541c04fecb4SDavid Teigland 		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
542d022509dSDavid Teigland 
543c7be761aSDavid Teigland 		spin_lock(&ls->ls_rsbtbl[bucket].lock);
544c04fecb4SDavid Teigland 		if (!RB_EMPTY_ROOT(tree)) {
545c04fecb4SDavid Teigland 			node = rb_first(tree);
5469beb3bf5SBob Peterson 			r = rb_entry(node, struct dlm_rsb, res_hashnode);
547892c4467SDavid Teigland 			dlm_hold_rsb(r);
548892c4467SDavid Teigland 			ri->rsb = r;
549892c4467SDavid Teigland 			ri->bucket = bucket;
550c7be761aSDavid Teigland 			spin_unlock(&ls->ls_rsbtbl[bucket].lock);
551892c4467SDavid Teigland 			*pos = n;
552d022509dSDavid Teigland 			return ri;
553d022509dSDavid Teigland 		}
554c7be761aSDavid Teigland 		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
555892c4467SDavid Teigland 	}
556892c4467SDavid Teigland }
557d022509dSDavid Teigland 
table_seq_next(struct seq_file * seq,void * iter_ptr,loff_t * pos)558892c4467SDavid Teigland static void *table_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos)
559d022509dSDavid Teigland {
560892c4467SDavid Teigland 	struct dlm_ls *ls = seq->private;
561892c4467SDavid Teigland 	struct rsbtbl_iter *ri = iter_ptr;
562c04fecb4SDavid Teigland 	struct rb_root *tree;
5639beb3bf5SBob Peterson 	struct rb_node *next;
564892c4467SDavid Teigland 	struct dlm_rsb *r, *rp;
565d022509dSDavid Teigland 	loff_t n = *pos;
566892c4467SDavid Teigland 	unsigned bucket;
567c04fecb4SDavid Teigland 	int toss = (seq->op == &format4_seq_ops);
568d022509dSDavid Teigland 
569892c4467SDavid Teigland 	bucket = n >> 32;
570d022509dSDavid Teigland 
571892c4467SDavid Teigland 	/*
572892c4467SDavid Teigland 	 * move to the next rsb in the same bucket
573892c4467SDavid Teigland 	 */
574d022509dSDavid Teigland 
575c7be761aSDavid Teigland 	spin_lock(&ls->ls_rsbtbl[bucket].lock);
576892c4467SDavid Teigland 	rp = ri->rsb;
5779beb3bf5SBob Peterson 	next = rb_next(&rp->res_hashnode);
578892c4467SDavid Teigland 
5799beb3bf5SBob Peterson 	if (next) {
5809beb3bf5SBob Peterson 		r = rb_entry(next, struct dlm_rsb, res_hashnode);
581892c4467SDavid Teigland 		dlm_hold_rsb(r);
582892c4467SDavid Teigland 		ri->rsb = r;
583c7be761aSDavid Teigland 		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
584892c4467SDavid Teigland 		dlm_put_rsb(rp);
585892c4467SDavid Teigland 		++*pos;
586d022509dSDavid Teigland 		return ri;
587d022509dSDavid Teigland 	}
588c7be761aSDavid Teigland 	spin_unlock(&ls->ls_rsbtbl[bucket].lock);
589892c4467SDavid Teigland 	dlm_put_rsb(rp);
590d022509dSDavid Teigland 
591892c4467SDavid Teigland 	/*
592892c4467SDavid Teigland 	 * move to the first rsb in the next non-empty bucket
593892c4467SDavid Teigland 	 */
594892c4467SDavid Teigland 
595892c4467SDavid Teigland 	/* zero the entry */
596892c4467SDavid Teigland 	n &= ~((1LL << 32) - 1);
597892c4467SDavid Teigland 
598892c4467SDavid Teigland 	while (1) {
599892c4467SDavid Teigland 		bucket++;
600892c4467SDavid Teigland 		n += 1LL << 32;
601892c4467SDavid Teigland 
602892c4467SDavid Teigland 		if (bucket >= ls->ls_rsbtbl_size) {
603892c4467SDavid Teigland 			kfree(ri);
60492c48950SAlexander Aring 			++*pos;
605892c4467SDavid Teigland 			return NULL;
606892c4467SDavid Teigland 		}
607c04fecb4SDavid Teigland 		tree = toss ? &ls->ls_rsbtbl[bucket].toss : &ls->ls_rsbtbl[bucket].keep;
608892c4467SDavid Teigland 
609c7be761aSDavid Teigland 		spin_lock(&ls->ls_rsbtbl[bucket].lock);
610c04fecb4SDavid Teigland 		if (!RB_EMPTY_ROOT(tree)) {
611c04fecb4SDavid Teigland 			next = rb_first(tree);
6129beb3bf5SBob Peterson 			r = rb_entry(next, struct dlm_rsb, res_hashnode);
613892c4467SDavid Teigland 			dlm_hold_rsb(r);
614892c4467SDavid Teigland 			ri->rsb = r;
615892c4467SDavid Teigland 			ri->bucket = bucket;
616c7be761aSDavid Teigland 			spin_unlock(&ls->ls_rsbtbl[bucket].lock);
617892c4467SDavid Teigland 			*pos = n;
618892c4467SDavid Teigland 			return ri;
619892c4467SDavid Teigland 		}
620c7be761aSDavid Teigland 		spin_unlock(&ls->ls_rsbtbl[bucket].lock);
621892c4467SDavid Teigland 	}
622892c4467SDavid Teigland }
623892c4467SDavid Teigland 
table_seq_stop(struct seq_file * seq,void * iter_ptr)624892c4467SDavid Teigland static void table_seq_stop(struct seq_file *seq, void *iter_ptr)
625892c4467SDavid Teigland {
626892c4467SDavid Teigland 	struct rsbtbl_iter *ri = iter_ptr;
627892c4467SDavid Teigland 
628892c4467SDavid Teigland 	if (ri) {
629892c4467SDavid Teigland 		dlm_put_rsb(ri->rsb);
630892c4467SDavid Teigland 		kfree(ri);
631892c4467SDavid Teigland 	}
632892c4467SDavid Teigland }
633892c4467SDavid Teigland 
63488e9d34cSJames Morris static const struct seq_operations format1_seq_ops = {
635892c4467SDavid Teigland 	.start = table_seq_start,
636892c4467SDavid Teigland 	.next  = table_seq_next,
637892c4467SDavid Teigland 	.stop  = table_seq_stop,
638892c4467SDavid Teigland 	.show  = table_seq_show,
639d022509dSDavid Teigland };
640d022509dSDavid Teigland 
64188e9d34cSJames Morris static const struct seq_operations format2_seq_ops = {
642892c4467SDavid Teigland 	.start = table_seq_start,
643892c4467SDavid Teigland 	.next  = table_seq_next,
644892c4467SDavid Teigland 	.stop  = table_seq_stop,
645892c4467SDavid Teigland 	.show  = table_seq_show,
646892c4467SDavid Teigland };
647892c4467SDavid Teigland 
64888e9d34cSJames Morris static const struct seq_operations format3_seq_ops = {
649892c4467SDavid Teigland 	.start = table_seq_start,
650892c4467SDavid Teigland 	.next  = table_seq_next,
651892c4467SDavid Teigland 	.stop  = table_seq_stop,
652892c4467SDavid Teigland 	.show  = table_seq_show,
653892c4467SDavid Teigland };
654892c4467SDavid Teigland 
655c04fecb4SDavid Teigland static const struct seq_operations format4_seq_ops = {
656c04fecb4SDavid Teigland 	.start = table_seq_start,
657c04fecb4SDavid Teigland 	.next  = table_seq_next,
658c04fecb4SDavid Teigland 	.stop  = table_seq_stop,
659c04fecb4SDavid Teigland 	.show  = table_seq_show,
660c04fecb4SDavid Teigland };
661c04fecb4SDavid Teigland 
662541adb0dSAlexander Aring static const struct seq_operations format5_seq_ops = {
663541adb0dSAlexander Aring 	.start = table_seq_start,
664541adb0dSAlexander Aring 	.next  = table_seq_next,
665541adb0dSAlexander Aring 	.stop  = table_seq_stop,
666541adb0dSAlexander Aring 	.show  = table_seq_show,
667541adb0dSAlexander Aring };
668541adb0dSAlexander Aring 
669892c4467SDavid Teigland static const struct file_operations format1_fops;
670892c4467SDavid Teigland static const struct file_operations format2_fops;
671892c4467SDavid Teigland static const struct file_operations format3_fops;
672c04fecb4SDavid Teigland static const struct file_operations format4_fops;
673541adb0dSAlexander Aring static const struct file_operations format5_fops;
674892c4467SDavid Teigland 
table_open1(struct inode * inode,struct file * file)675079d37dfSEric Ren static int table_open1(struct inode *inode, struct file *file)
676d022509dSDavid Teigland {
677d022509dSDavid Teigland 	struct seq_file *seq;
678079d37dfSEric Ren 	int ret;
679d022509dSDavid Teigland 
680892c4467SDavid Teigland 	ret = seq_open(file, &format1_seq_ops);
681079d37dfSEric Ren 	if (ret)
682079d37dfSEric Ren 		return ret;
683892c4467SDavid Teigland 
684079d37dfSEric Ren 	seq = file->private_data;
685079d37dfSEric Ren 	seq->private = inode->i_private; /* the dlm_ls */
686079d37dfSEric Ren 	return 0;
687079d37dfSEric Ren }
688079d37dfSEric Ren 
table_open2(struct inode * inode,struct file * file)689079d37dfSEric Ren static int table_open2(struct inode *inode, struct file *file)
690079d37dfSEric Ren {
691079d37dfSEric Ren 	struct seq_file *seq;
692079d37dfSEric Ren 	int ret;
693079d37dfSEric Ren 
694079d37dfSEric Ren 	ret = seq_open(file, &format2_seq_ops);
695079d37dfSEric Ren 	if (ret)
696079d37dfSEric Ren 		return ret;
697079d37dfSEric Ren 
698079d37dfSEric Ren 	seq = file->private_data;
699079d37dfSEric Ren 	seq->private = inode->i_private; /* the dlm_ls */
700079d37dfSEric Ren 	return 0;
701079d37dfSEric Ren }
702079d37dfSEric Ren 
table_write2(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)7035054e79dSAlexander Aring static ssize_t table_write2(struct file *file, const char __user *user_buf,
7045054e79dSAlexander Aring 			    size_t count, loff_t *ppos)
7055054e79dSAlexander Aring {
7065054e79dSAlexander Aring 	struct seq_file *seq = file->private_data;
7075054e79dSAlexander Aring 	int n, len, lkb_nodeid, lkb_status, error;
7086a628fa4SAlexander Aring 	char name[DLM_RESNAME_MAXLEN + 1] = {};
7095054e79dSAlexander Aring 	struct dlm_ls *ls = seq->private;
7105054e79dSAlexander Aring 	unsigned int lkb_flags;
7115054e79dSAlexander Aring 	char buf[256] = {};
7125054e79dSAlexander Aring 	uint32_t lkb_id;
7135054e79dSAlexander Aring 
7145054e79dSAlexander Aring 	if (copy_from_user(buf, user_buf,
7155054e79dSAlexander Aring 			   min_t(size_t, sizeof(buf) - 1, count)))
7165054e79dSAlexander Aring 		return -EFAULT;
7175054e79dSAlexander Aring 
7185054e79dSAlexander Aring 	n = sscanf(buf, "%x %" __stringify(DLM_RESNAME_MAXLEN) "s %x %d %d",
7195054e79dSAlexander Aring 		   &lkb_id, name, &lkb_flags, &lkb_nodeid, &lkb_status);
7205054e79dSAlexander Aring 	if (n != 5)
7215054e79dSAlexander Aring 		return -EINVAL;
7225054e79dSAlexander Aring 
7235054e79dSAlexander Aring 	len = strnlen(name, DLM_RESNAME_MAXLEN);
7245054e79dSAlexander Aring 	error = dlm_debug_add_lkb(ls, lkb_id, name, len, lkb_flags,
7255054e79dSAlexander Aring 				  lkb_nodeid, lkb_status);
7265054e79dSAlexander Aring 	if (error)
7275054e79dSAlexander Aring 		return error;
7285054e79dSAlexander Aring 
7295054e79dSAlexander Aring 	return count;
7305054e79dSAlexander Aring }
7315054e79dSAlexander Aring 
table_open3(struct inode * inode,struct file * file)732079d37dfSEric Ren static int table_open3(struct inode *inode, struct file *file)
733079d37dfSEric Ren {
734079d37dfSEric Ren 	struct seq_file *seq;
735079d37dfSEric Ren 	int ret;
736079d37dfSEric Ren 
737079d37dfSEric Ren 	ret = seq_open(file, &format3_seq_ops);
738079d37dfSEric Ren 	if (ret)
739079d37dfSEric Ren 		return ret;
740079d37dfSEric Ren 
741079d37dfSEric Ren 	seq = file->private_data;
742079d37dfSEric Ren 	seq->private = inode->i_private; /* the dlm_ls */
743079d37dfSEric Ren 	return 0;
744079d37dfSEric Ren }
745079d37dfSEric Ren 
table_open4(struct inode * inode,struct file * file)746079d37dfSEric Ren static int table_open4(struct inode *inode, struct file *file)
747079d37dfSEric Ren {
748079d37dfSEric Ren 	struct seq_file *seq;
749079d37dfSEric Ren 	int ret;
750079d37dfSEric Ren 
751*528a422bSAlexander Aring 	ret = seq_open(file, &format4_seq_ops);
752541adb0dSAlexander Aring 	if (ret)
753541adb0dSAlexander Aring 		return ret;
754541adb0dSAlexander Aring 
755541adb0dSAlexander Aring 	seq = file->private_data;
756541adb0dSAlexander Aring 	seq->private = inode->i_private; /* the dlm_ls */
757541adb0dSAlexander Aring 	return 0;
758541adb0dSAlexander Aring }
759541adb0dSAlexander Aring 
table_open5(struct inode * inode,struct file * file)760541adb0dSAlexander Aring static int table_open5(struct inode *inode, struct file *file)
761541adb0dSAlexander Aring {
762541adb0dSAlexander Aring 	struct seq_file *seq;
763541adb0dSAlexander Aring 	int ret;
764541adb0dSAlexander Aring 
765541adb0dSAlexander Aring 	ret = seq_open(file, &format5_seq_ops);
766d022509dSDavid Teigland 	if (ret)
767d022509dSDavid Teigland 		return ret;
768d022509dSDavid Teigland 
769d022509dSDavid Teigland 	seq = file->private_data;
770892c4467SDavid Teigland 	seq->private = inode->i_private; /* the dlm_ls */
771d022509dSDavid Teigland 	return 0;
772d022509dSDavid Teigland }
773d022509dSDavid Teigland 
774892c4467SDavid Teigland static const struct file_operations format1_fops = {
775d022509dSDavid Teigland 	.owner   = THIS_MODULE,
776079d37dfSEric Ren 	.open    = table_open1,
777892c4467SDavid Teigland 	.read    = seq_read,
778892c4467SDavid Teigland 	.llseek  = seq_lseek,
779892c4467SDavid Teigland 	.release = seq_release
780892c4467SDavid Teigland };
781892c4467SDavid Teigland 
782892c4467SDavid Teigland static const struct file_operations format2_fops = {
783892c4467SDavid Teigland 	.owner   = THIS_MODULE,
784079d37dfSEric Ren 	.open    = table_open2,
785892c4467SDavid Teigland 	.read    = seq_read,
7865054e79dSAlexander Aring 	.write   = table_write2,
787892c4467SDavid Teigland 	.llseek  = seq_lseek,
788892c4467SDavid Teigland 	.release = seq_release
789892c4467SDavid Teigland };
790892c4467SDavid Teigland 
791892c4467SDavid Teigland static const struct file_operations format3_fops = {
792892c4467SDavid Teigland 	.owner   = THIS_MODULE,
793079d37dfSEric Ren 	.open    = table_open3,
794d022509dSDavid Teigland 	.read    = seq_read,
795d022509dSDavid Teigland 	.llseek  = seq_lseek,
796d022509dSDavid Teigland 	.release = seq_release
797d022509dSDavid Teigland };
798d022509dSDavid Teigland 
799c04fecb4SDavid Teigland static const struct file_operations format4_fops = {
800c04fecb4SDavid Teigland 	.owner   = THIS_MODULE,
801079d37dfSEric Ren 	.open    = table_open4,
802c04fecb4SDavid Teigland 	.read    = seq_read,
803c04fecb4SDavid Teigland 	.llseek  = seq_lseek,
804c04fecb4SDavid Teigland 	.release = seq_release
805c04fecb4SDavid Teigland };
806c04fecb4SDavid Teigland 
807541adb0dSAlexander Aring static const struct file_operations format5_fops = {
808541adb0dSAlexander Aring 	.owner   = THIS_MODULE,
809541adb0dSAlexander Aring 	.open    = table_open5,
810541adb0dSAlexander Aring 	.read    = seq_read,
811541adb0dSAlexander Aring 	.llseek  = seq_lseek,
812541adb0dSAlexander Aring 	.release = seq_release
813541adb0dSAlexander Aring };
814541adb0dSAlexander Aring 
815d022509dSDavid Teigland /*
8165de6319bSDavid Teigland  * dump lkb's on the ls_waiters list
8175de6319bSDavid Teigland  */
waiters_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)8185de6319bSDavid Teigland static ssize_t waiters_read(struct file *file, char __user *userbuf,
8195de6319bSDavid Teigland 			    size_t count, loff_t *ppos)
8205de6319bSDavid Teigland {
8215de6319bSDavid Teigland 	struct dlm_ls *ls = file->private_data;
8225de6319bSDavid Teigland 	struct dlm_lkb *lkb;
82306442440SDavid Teigland 	size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;
8245de6319bSDavid Teigland 
8255de6319bSDavid Teigland 	mutex_lock(&debug_buf_lock);
8265de6319bSDavid Teigland 	mutex_lock(&ls->ls_waiters_mutex);
8275de6319bSDavid Teigland 	memset(debug_buf, 0, sizeof(debug_buf));
8285de6319bSDavid Teigland 
8295de6319bSDavid Teigland 	list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
83006442440SDavid Teigland 		ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
8315de6319bSDavid Teigland 			       lkb->lkb_id, lkb->lkb_wait_type,
8325de6319bSDavid Teigland 			       lkb->lkb_nodeid, lkb->lkb_resource->res_name);
83306442440SDavid Teigland 		if (ret >= len - pos)
83406442440SDavid Teigland 			break;
83506442440SDavid Teigland 		pos += ret;
8365de6319bSDavid Teigland 	}
8375de6319bSDavid Teigland 	mutex_unlock(&ls->ls_waiters_mutex);
8385de6319bSDavid Teigland 
8395de6319bSDavid Teigland 	rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
8405de6319bSDavid Teigland 	mutex_unlock(&debug_buf_lock);
8415de6319bSDavid Teigland 	return rv;
8425de6319bSDavid Teigland }
8435de6319bSDavid Teigland 
waiters_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)84463eab2b0SAlexander Aring static ssize_t waiters_write(struct file *file, const char __user *user_buf,
84563eab2b0SAlexander Aring 			     size_t count, loff_t *ppos)
84663eab2b0SAlexander Aring {
84763eab2b0SAlexander Aring 	struct dlm_ls *ls = file->private_data;
84863eab2b0SAlexander Aring 	int mstype, to_nodeid;
84963eab2b0SAlexander Aring 	char buf[128] = {};
85063eab2b0SAlexander Aring 	uint32_t lkb_id;
85163eab2b0SAlexander Aring 	int n, error;
85263eab2b0SAlexander Aring 
85363eab2b0SAlexander Aring 	if (copy_from_user(buf, user_buf,
85463eab2b0SAlexander Aring 			   min_t(size_t, sizeof(buf) - 1, count)))
85563eab2b0SAlexander Aring 		return -EFAULT;
85663eab2b0SAlexander Aring 
85763eab2b0SAlexander Aring 	n = sscanf(buf, "%x %d %d", &lkb_id, &mstype, &to_nodeid);
85863eab2b0SAlexander Aring 	if (n != 3)
85963eab2b0SAlexander Aring 		return -EINVAL;
86063eab2b0SAlexander Aring 
86163eab2b0SAlexander Aring 	error = dlm_debug_add_lkb_to_waiters(ls, lkb_id, mstype, to_nodeid);
86263eab2b0SAlexander Aring 	if (error)
86363eab2b0SAlexander Aring 		return error;
86463eab2b0SAlexander Aring 
86563eab2b0SAlexander Aring 	return count;
86663eab2b0SAlexander Aring }
86763eab2b0SAlexander Aring 
86800977a59SArjan van de Ven static const struct file_operations waiters_fops = {
8695de6319bSDavid Teigland 	.owner   = THIS_MODULE,
870234e3405SStephen Boyd 	.open    = simple_open,
8716038f373SArnd Bergmann 	.read    = waiters_read,
87263eab2b0SAlexander Aring 	.write   = waiters_write,
8736038f373SArnd Bergmann 	.llseek  = default_llseek,
8745de6319bSDavid Teigland };
8755de6319bSDavid Teigland 
dlm_delete_debug_file(struct dlm_ls * ls)876d022509dSDavid Teigland void dlm_delete_debug_file(struct dlm_ls *ls)
877d022509dSDavid Teigland {
878d022509dSDavid Teigland 	debugfs_remove(ls->ls_debug_rsb_dentry);
879d022509dSDavid Teigland 	debugfs_remove(ls->ls_debug_waiters_dentry);
880d022509dSDavid Teigland 	debugfs_remove(ls->ls_debug_locks_dentry);
881d022509dSDavid Teigland 	debugfs_remove(ls->ls_debug_all_dentry);
882c04fecb4SDavid Teigland 	debugfs_remove(ls->ls_debug_toss_dentry);
883541adb0dSAlexander Aring 	debugfs_remove(ls->ls_debug_queued_asts_dentry);
884d022509dSDavid Teigland }
885d022509dSDavid Teigland 
dlm_state_show(struct seq_file * file,void * offset)8865b2f981fSAlexander Aring static int dlm_state_show(struct seq_file *file, void *offset)
8875b2f981fSAlexander Aring {
8885b2f981fSAlexander Aring 	seq_printf(file, "%s\n", dlm_midcomms_state(file->private));
8895b2f981fSAlexander Aring 	return 0;
8905b2f981fSAlexander Aring }
8915b2f981fSAlexander Aring DEFINE_SHOW_ATTRIBUTE(dlm_state);
8925b2f981fSAlexander Aring 
dlm_flags_show(struct seq_file * file,void * offset)8935b2f981fSAlexander Aring static int dlm_flags_show(struct seq_file *file, void *offset)
8945b2f981fSAlexander Aring {
8955b2f981fSAlexander Aring 	seq_printf(file, "%lu\n", dlm_midcomms_flags(file->private));
8965b2f981fSAlexander Aring 	return 0;
8975b2f981fSAlexander Aring }
8985b2f981fSAlexander Aring DEFINE_SHOW_ATTRIBUTE(dlm_flags);
8995b2f981fSAlexander Aring 
dlm_send_queue_cnt_show(struct seq_file * file,void * offset)9005b2f981fSAlexander Aring static int dlm_send_queue_cnt_show(struct seq_file *file, void *offset)
9015b2f981fSAlexander Aring {
9025b2f981fSAlexander Aring 	seq_printf(file, "%d\n", dlm_midcomms_send_queue_cnt(file->private));
9035b2f981fSAlexander Aring 	return 0;
9045b2f981fSAlexander Aring }
9055b2f981fSAlexander Aring DEFINE_SHOW_ATTRIBUTE(dlm_send_queue_cnt);
9065b2f981fSAlexander Aring 
dlm_version_show(struct seq_file * file,void * offset)9075b2f981fSAlexander Aring static int dlm_version_show(struct seq_file *file, void *offset)
9085b2f981fSAlexander Aring {
9095b2f981fSAlexander Aring 	seq_printf(file, "0x%08x\n", dlm_midcomms_version(file->private));
9105b2f981fSAlexander Aring 	return 0;
9115b2f981fSAlexander Aring }
9125b2f981fSAlexander Aring DEFINE_SHOW_ATTRIBUTE(dlm_version);
9135b2f981fSAlexander Aring 
dlm_rawmsg_write(struct file * fp,const char __user * user_buf,size_t count,loff_t * ppos)9149af5b8f0SAlexander Aring static ssize_t dlm_rawmsg_write(struct file *fp, const char __user *user_buf,
9159af5b8f0SAlexander Aring 				size_t count, loff_t *ppos)
9169af5b8f0SAlexander Aring {
9179af5b8f0SAlexander Aring 	void *buf;
9189af5b8f0SAlexander Aring 	int ret;
9199af5b8f0SAlexander Aring 
9209af5b8f0SAlexander Aring 	if (count > PAGE_SIZE || count < sizeof(struct dlm_header))
9219af5b8f0SAlexander Aring 		return -EINVAL;
9229af5b8f0SAlexander Aring 
9239af5b8f0SAlexander Aring 	buf = kmalloc(PAGE_SIZE, GFP_NOFS);
9249af5b8f0SAlexander Aring 	if (!buf)
9259af5b8f0SAlexander Aring 		return -ENOMEM;
9269af5b8f0SAlexander Aring 
9279af5b8f0SAlexander Aring 	if (copy_from_user(buf, user_buf, count)) {
9289af5b8f0SAlexander Aring 		ret = -EFAULT;
9299af5b8f0SAlexander Aring 		goto out;
9309af5b8f0SAlexander Aring 	}
9319af5b8f0SAlexander Aring 
9329af5b8f0SAlexander Aring 	ret = dlm_midcomms_rawmsg_send(fp->private_data, buf, count);
9339af5b8f0SAlexander Aring 	if (ret)
9349af5b8f0SAlexander Aring 		goto out;
9359af5b8f0SAlexander Aring 
9369af5b8f0SAlexander Aring 	kfree(buf);
9379af5b8f0SAlexander Aring 	return count;
9389af5b8f0SAlexander Aring 
9399af5b8f0SAlexander Aring out:
9409af5b8f0SAlexander Aring 	kfree(buf);
9419af5b8f0SAlexander Aring 	return ret;
9429af5b8f0SAlexander Aring }
9439af5b8f0SAlexander Aring 
9449af5b8f0SAlexander Aring static const struct file_operations dlm_rawmsg_fops = {
9459af5b8f0SAlexander Aring 	.open	= simple_open,
9469af5b8f0SAlexander Aring 	.write	= dlm_rawmsg_write,
9479af5b8f0SAlexander Aring 	.llseek	= no_llseek,
9489af5b8f0SAlexander Aring };
9499af5b8f0SAlexander Aring 
dlm_create_debug_comms_file(int nodeid,void * data)9505b2f981fSAlexander Aring void *dlm_create_debug_comms_file(int nodeid, void *data)
9515b2f981fSAlexander Aring {
9525b2f981fSAlexander Aring 	struct dentry *d_node;
9535b2f981fSAlexander Aring 	char name[256];
9545b2f981fSAlexander Aring 
9555b2f981fSAlexander Aring 	memset(name, 0, sizeof(name));
9565b2f981fSAlexander Aring 	snprintf(name, 256, "%d", nodeid);
9575b2f981fSAlexander Aring 
9585b2f981fSAlexander Aring 	d_node = debugfs_create_dir(name, dlm_comms);
9595b2f981fSAlexander Aring 	debugfs_create_file("state", 0444, d_node, data, &dlm_state_fops);
9605b2f981fSAlexander Aring 	debugfs_create_file("flags", 0444, d_node, data, &dlm_flags_fops);
9615b2f981fSAlexander Aring 	debugfs_create_file("send_queue_count", 0444, d_node, data,
9625b2f981fSAlexander Aring 			    &dlm_send_queue_cnt_fops);
9635b2f981fSAlexander Aring 	debugfs_create_file("version", 0444, d_node, data, &dlm_version_fops);
9649af5b8f0SAlexander Aring 	debugfs_create_file("rawmsg", 0200, d_node, data, &dlm_rawmsg_fops);
9655b2f981fSAlexander Aring 
9665b2f981fSAlexander Aring 	return d_node;
9675b2f981fSAlexander Aring }
9685b2f981fSAlexander Aring 
dlm_delete_debug_comms_file(void * ctx)9695b2f981fSAlexander Aring void dlm_delete_debug_comms_file(void *ctx)
9705b2f981fSAlexander Aring {
9715b2f981fSAlexander Aring 	debugfs_remove(ctx);
9725b2f981fSAlexander Aring }
9735b2f981fSAlexander Aring 
dlm_create_debug_file(struct dlm_ls * ls)974a48f9721SGreg Kroah-Hartman void dlm_create_debug_file(struct dlm_ls *ls)
975e7fd4179SDavid Teigland {
9764a31e3c8SChristophe JAILLET 	/* Reserve enough space for the longest file name */
9774a31e3c8SChristophe JAILLET 	char name[DLM_LOCKSPACE_LEN + sizeof("_queued_asts")];
9785de6319bSDavid Teigland 
979d022509dSDavid Teigland 	/* format 1 */
980d022509dSDavid Teigland 
9815de6319bSDavid Teigland 	ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
982e7fd4179SDavid Teigland 						      S_IFREG | S_IRUGO,
983e7fd4179SDavid Teigland 						      dlm_root,
984e7fd4179SDavid Teigland 						      ls,
985892c4467SDavid Teigland 						      &format1_fops);
9865de6319bSDavid Teigland 
987d022509dSDavid Teigland 	/* format 2 */
9885de6319bSDavid Teigland 
9899dd592d7SDavid Teigland 	memset(name, 0, sizeof(name));
9904bc46c04SChristophe JAILLET 	snprintf(name, sizeof(name), "%s_locks", ls->ls_name);
9919dd592d7SDavid Teigland 
992ac90a255SDavid Teigland 	ls->ls_debug_locks_dentry = debugfs_create_file(name,
9935054e79dSAlexander Aring 							0644,
9949dd592d7SDavid Teigland 							dlm_root,
9959dd592d7SDavid Teigland 							ls,
996892c4467SDavid Teigland 							&format2_fops);
997d022509dSDavid Teigland 
998d022509dSDavid Teigland 	/* format 3 */
999d022509dSDavid Teigland 
1000d022509dSDavid Teigland 	memset(name, 0, sizeof(name));
10014bc46c04SChristophe JAILLET 	snprintf(name, sizeof(name), "%s_all", ls->ls_name);
1002d022509dSDavid Teigland 
1003d022509dSDavid Teigland 	ls->ls_debug_all_dentry = debugfs_create_file(name,
1004d022509dSDavid Teigland 						      S_IFREG | S_IRUGO,
1005d022509dSDavid Teigland 						      dlm_root,
1006d022509dSDavid Teigland 						      ls,
1007892c4467SDavid Teigland 						      &format3_fops);
1008d022509dSDavid Teigland 
1009c04fecb4SDavid Teigland 	/* format 4 */
1010c04fecb4SDavid Teigland 
1011c04fecb4SDavid Teigland 	memset(name, 0, sizeof(name));
10124bc46c04SChristophe JAILLET 	snprintf(name, sizeof(name), "%s_toss", ls->ls_name);
1013c04fecb4SDavid Teigland 
1014c04fecb4SDavid Teigland 	ls->ls_debug_toss_dentry = debugfs_create_file(name,
1015c04fecb4SDavid Teigland 						       S_IFREG | S_IRUGO,
1016c04fecb4SDavid Teigland 						       dlm_root,
1017c04fecb4SDavid Teigland 						       ls,
1018c04fecb4SDavid Teigland 						       &format4_fops);
1019c04fecb4SDavid Teigland 
1020d022509dSDavid Teigland 	memset(name, 0, sizeof(name));
10214bc46c04SChristophe JAILLET 	snprintf(name, sizeof(name), "%s_waiters", ls->ls_name);
1022d022509dSDavid Teigland 
1023d022509dSDavid Teigland 	ls->ls_debug_waiters_dentry = debugfs_create_file(name,
102463eab2b0SAlexander Aring 							  0644,
1025d022509dSDavid Teigland 							  dlm_root,
1026d022509dSDavid Teigland 							  ls,
1027d022509dSDavid Teigland 							  &waiters_fops);
1028541adb0dSAlexander Aring 
1029541adb0dSAlexander Aring 	/* format 5 */
1030541adb0dSAlexander Aring 
1031541adb0dSAlexander Aring 	memset(name, 0, sizeof(name));
10324bc46c04SChristophe JAILLET 	snprintf(name, sizeof(name), "%s_queued_asts", ls->ls_name);
1033541adb0dSAlexander Aring 
1034541adb0dSAlexander Aring 	ls->ls_debug_queued_asts_dentry = debugfs_create_file(name,
1035541adb0dSAlexander Aring 							      0644,
1036541adb0dSAlexander Aring 							      dlm_root,
1037541adb0dSAlexander Aring 							      ls,
1038541adb0dSAlexander Aring 							      &format5_fops);
1039e7fd4179SDavid Teigland }
1040e7fd4179SDavid Teigland 
dlm_register_debugfs(void)1041a48f9721SGreg Kroah-Hartman void __init dlm_register_debugfs(void)
1042e7fd4179SDavid Teigland {
10435de6319bSDavid Teigland 	mutex_init(&debug_buf_lock);
1044e7fd4179SDavid Teigland 	dlm_root = debugfs_create_dir("dlm", NULL);
10455b2f981fSAlexander Aring 	dlm_comms = debugfs_create_dir("comms", dlm_root);
1046e7fd4179SDavid Teigland }
1047e7fd4179SDavid Teigland 
dlm_unregister_debugfs(void)1048e7fd4179SDavid Teigland void dlm_unregister_debugfs(void)
1049e7fd4179SDavid Teigland {
1050e7fd4179SDavid Teigland 	debugfs_remove(dlm_root);
1051e7fd4179SDavid Teigland }
1052e7fd4179SDavid Teigland 
1053