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