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