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