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