xref: /openbmc/linux/fs/dlm/debug_fs.c (revision e868d61272caa648214046a096e5a6bfc068dc8c)
1 /******************************************************************************
2 *******************************************************************************
3 **
4 **  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
5 **
6 **  This copyrighted material is made available to anyone wishing to use,
7 **  modify, copy, or redistribute it subject to the terms and conditions
8 **  of the GNU General Public License v.2.
9 **
10 *******************************************************************************
11 ******************************************************************************/
12 
13 #include <linux/pagemap.h>
14 #include <linux/seq_file.h>
15 #include <linux/module.h>
16 #include <linux/ctype.h>
17 #include <linux/debugfs.h>
18 
19 #include "dlm_internal.h"
20 
21 #define DLM_DEBUG_BUF_LEN 4096
22 static char debug_buf[DLM_DEBUG_BUF_LEN];
23 static struct mutex debug_buf_lock;
24 
25 static struct dentry *dlm_root;
26 
27 struct rsb_iter {
28 	int entry;
29 	struct dlm_ls *ls;
30 	struct list_head *next;
31 	struct dlm_rsb *rsb;
32 };
33 
34 /*
35  * dump all rsb's in the lockspace hash table
36  */
37 
38 static char *print_lockmode(int mode)
39 {
40 	switch (mode) {
41 	case DLM_LOCK_IV:
42 		return "--";
43 	case DLM_LOCK_NL:
44 		return "NL";
45 	case DLM_LOCK_CR:
46 		return "CR";
47 	case DLM_LOCK_CW:
48 		return "CW";
49 	case DLM_LOCK_PR:
50 		return "PR";
51 	case DLM_LOCK_PW:
52 		return "PW";
53 	case DLM_LOCK_EX:
54 		return "EX";
55 	default:
56 		return "??";
57 	}
58 }
59 
60 static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
61 		       struct dlm_rsb *res)
62 {
63 	seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
64 
65 	if (lkb->lkb_status == DLM_LKSTS_CONVERT
66 	    || lkb->lkb_status == DLM_LKSTS_WAITING)
67 		seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
68 
69 	if (lkb->lkb_nodeid) {
70 		if (lkb->lkb_nodeid != res->res_nodeid)
71 			seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
72 				   lkb->lkb_remid);
73 		else
74 			seq_printf(s, " Master:     %08x", lkb->lkb_remid);
75 	}
76 
77 	if (lkb->lkb_wait_type)
78 		seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
79 
80 	seq_printf(s, "\n");
81 }
82 
83 static int print_resource(struct dlm_rsb *res, struct seq_file *s)
84 {
85 	struct dlm_lkb *lkb;
86 	int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
87 
88 	seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
89 	for (i = 0; i < res->res_length; i++) {
90 		if (isprint(res->res_name[i]))
91 			seq_printf(s, "%c", res->res_name[i]);
92 		else
93 			seq_printf(s, "%c", '.');
94 	}
95 	if (res->res_nodeid > 0)
96 		seq_printf(s, "\"  \nLocal Copy, Master is node %d\n",
97 			   res->res_nodeid);
98 	else if (res->res_nodeid == 0)
99 		seq_printf(s, "\"  \nMaster Copy\n");
100 	else if (res->res_nodeid == -1)
101 		seq_printf(s, "\"  \nLooking up master (lkid %x)\n",
102 			   res->res_first_lkid);
103 	else
104 		seq_printf(s, "\"  \nInvalid master %d\n", res->res_nodeid);
105 
106 	/* Print the LVB: */
107 	if (res->res_lvbptr) {
108 		seq_printf(s, "LVB: ");
109 		for (i = 0; i < lvblen; i++) {
110 			if (i == lvblen / 2)
111 				seq_printf(s, "\n     ");
112 			seq_printf(s, "%02x ",
113 				   (unsigned char) res->res_lvbptr[i]);
114 		}
115 		if (rsb_flag(res, RSB_VALNOTVALID))
116 			seq_printf(s, " (INVALID)");
117 		seq_printf(s, "\n");
118 	}
119 
120 	root_list = !list_empty(&res->res_root_list);
121 	recover_list = !list_empty(&res->res_recover_list);
122 
123 	if (root_list || recover_list) {
124 		seq_printf(s, "Recovery: root %d recover %d flags %lx "
125 			   "count %d\n", root_list, recover_list,
126 			   res->res_flags, res->res_recover_locks_count);
127 	}
128 
129 	/* Print the locks attached to this resource */
130 	seq_printf(s, "Granted Queue\n");
131 	list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
132 		print_lock(s, lkb, res);
133 
134 	seq_printf(s, "Conversion Queue\n");
135 	list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
136 		print_lock(s, lkb, res);
137 
138 	seq_printf(s, "Waiting Queue\n");
139 	list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
140 		print_lock(s, lkb, res);
141 
142 	if (list_empty(&res->res_lookup))
143 		goto out;
144 
145 	seq_printf(s, "Lookup Queue\n");
146 	list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
147 		seq_printf(s, "%08x %s", lkb->lkb_id,
148 			   print_lockmode(lkb->lkb_rqmode));
149 		if (lkb->lkb_wait_type)
150 			seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
151 		seq_printf(s, "\n");
152 	}
153  out:
154 	return 0;
155 }
156 
157 static int rsb_iter_next(struct rsb_iter *ri)
158 {
159 	struct dlm_ls *ls = ri->ls;
160 	int i;
161 
162 	if (!ri->next) {
163  top:
164 		/* Find the next non-empty hash bucket */
165 		for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
166 			read_lock(&ls->ls_rsbtbl[i].lock);
167 			if (!list_empty(&ls->ls_rsbtbl[i].list)) {
168 				ri->next = ls->ls_rsbtbl[i].list.next;
169 				read_unlock(&ls->ls_rsbtbl[i].lock);
170 				break;
171 			}
172 			read_unlock(&ls->ls_rsbtbl[i].lock);
173                 }
174 		ri->entry = i;
175 
176 		if (ri->entry >= ls->ls_rsbtbl_size)
177 			return 1;
178 	} else {
179 		i = ri->entry;
180 		read_lock(&ls->ls_rsbtbl[i].lock);
181 		ri->next = ri->next->next;
182 		if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
183 			/* End of list - move to next bucket */
184 			ri->next = NULL;
185 			ri->entry++;
186 			read_unlock(&ls->ls_rsbtbl[i].lock);
187 			goto top;
188                 }
189 		read_unlock(&ls->ls_rsbtbl[i].lock);
190 	}
191 	ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
192 
193 	return 0;
194 }
195 
196 static void rsb_iter_free(struct rsb_iter *ri)
197 {
198 	kfree(ri);
199 }
200 
201 static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
202 {
203 	struct rsb_iter *ri;
204 
205 	ri = kmalloc(sizeof *ri, GFP_KERNEL);
206 	if (!ri)
207 		return NULL;
208 
209 	ri->ls = ls;
210 	ri->entry = 0;
211 	ri->next = NULL;
212 
213 	if (rsb_iter_next(ri)) {
214 		rsb_iter_free(ri);
215 		return NULL;
216 	}
217 
218 	return ri;
219 }
220 
221 static void *rsb_seq_start(struct seq_file *file, loff_t *pos)
222 {
223 	struct rsb_iter *ri;
224 	loff_t n = *pos;
225 
226 	ri = rsb_iter_init(file->private);
227 	if (!ri)
228 		return NULL;
229 
230 	while (n--) {
231 		if (rsb_iter_next(ri)) {
232 			rsb_iter_free(ri);
233 			return NULL;
234 		}
235 	}
236 
237 	return ri;
238 }
239 
240 static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
241 {
242 	struct rsb_iter *ri = iter_ptr;
243 
244 	(*pos)++;
245 
246 	if (rsb_iter_next(ri)) {
247 		rsb_iter_free(ri);
248 		return NULL;
249 	}
250 
251 	return ri;
252 }
253 
254 static void rsb_seq_stop(struct seq_file *file, void *iter_ptr)
255 {
256 	/* nothing for now */
257 }
258 
259 static int rsb_seq_show(struct seq_file *file, void *iter_ptr)
260 {
261 	struct rsb_iter *ri = iter_ptr;
262 
263 	print_resource(ri->rsb, file);
264 
265 	return 0;
266 }
267 
268 static struct seq_operations rsb_seq_ops = {
269 	.start = rsb_seq_start,
270 	.next  = rsb_seq_next,
271 	.stop  = rsb_seq_stop,
272 	.show  = rsb_seq_show,
273 };
274 
275 static int rsb_open(struct inode *inode, struct file *file)
276 {
277 	struct seq_file *seq;
278 	int ret;
279 
280 	ret = seq_open(file, &rsb_seq_ops);
281 	if (ret)
282 		return ret;
283 
284 	seq = file->private_data;
285 	seq->private = inode->i_private;
286 
287 	return 0;
288 }
289 
290 static const struct file_operations rsb_fops = {
291 	.owner   = THIS_MODULE,
292 	.open    = rsb_open,
293 	.read    = seq_read,
294 	.llseek  = seq_lseek,
295 	.release = seq_release
296 };
297 
298 /*
299  * dump lkb's on the ls_waiters list
300  */
301 
302 static int waiters_open(struct inode *inode, struct file *file)
303 {
304 	file->private_data = inode->i_private;
305 	return 0;
306 }
307 
308 static ssize_t waiters_read(struct file *file, char __user *userbuf,
309 			    size_t count, loff_t *ppos)
310 {
311 	struct dlm_ls *ls = file->private_data;
312 	struct dlm_lkb *lkb;
313 	size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;
314 
315 	mutex_lock(&debug_buf_lock);
316 	mutex_lock(&ls->ls_waiters_mutex);
317 	memset(debug_buf, 0, sizeof(debug_buf));
318 
319 	list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
320 		ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
321 			       lkb->lkb_id, lkb->lkb_wait_type,
322 			       lkb->lkb_nodeid, lkb->lkb_resource->res_name);
323 		if (ret >= len - pos)
324 			break;
325 		pos += ret;
326 	}
327 	mutex_unlock(&ls->ls_waiters_mutex);
328 
329 	rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
330 	mutex_unlock(&debug_buf_lock);
331 	return rv;
332 }
333 
334 static const struct file_operations waiters_fops = {
335 	.owner   = THIS_MODULE,
336 	.open    = waiters_open,
337 	.read    = waiters_read
338 };
339 
340 int dlm_create_debug_file(struct dlm_ls *ls)
341 {
342 	char name[DLM_LOCKSPACE_LEN+8];
343 
344 	ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
345 						      S_IFREG | S_IRUGO,
346 						      dlm_root,
347 						      ls,
348 						      &rsb_fops);
349 	if (!ls->ls_debug_rsb_dentry)
350 		return -ENOMEM;
351 
352 	memset(name, 0, sizeof(name));
353 	snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name);
354 
355 	ls->ls_debug_waiters_dentry = debugfs_create_file(name,
356 							  S_IFREG | S_IRUGO,
357 							  dlm_root,
358 							  ls,
359 							  &waiters_fops);
360 	if (!ls->ls_debug_waiters_dentry) {
361 		debugfs_remove(ls->ls_debug_rsb_dentry);
362 		return -ENOMEM;
363 	}
364 
365 	return 0;
366 }
367 
368 void dlm_delete_debug_file(struct dlm_ls *ls)
369 {
370 	if (ls->ls_debug_rsb_dentry)
371 		debugfs_remove(ls->ls_debug_rsb_dentry);
372 	if (ls->ls_debug_waiters_dentry)
373 		debugfs_remove(ls->ls_debug_waiters_dentry);
374 }
375 
376 int dlm_register_debugfs(void)
377 {
378 	mutex_init(&debug_buf_lock);
379 	dlm_root = debugfs_create_dir("dlm", NULL);
380 	return dlm_root ? 0 : -ENOMEM;
381 }
382 
383 void dlm_unregister_debugfs(void)
384 {
385 	debugfs_remove(dlm_root);
386 }
387 
388