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