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 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, kref_read(&res->refs),
 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                        kref_read(&mle->mle_refs));
 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 int debug_release(struct inode *inode, struct file *file)
 351{
 352        free_page((unsigned long)file->private_data);
 353        return 0;
 354}
 355
 356static ssize_t debug_read(struct file *file, char __user *buf,
 357                          size_t nbytes, loff_t *ppos)
 358{
 359        return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
 360                                       i_size_read(file->f_mapping->host));
 361}
 362/* end - util funcs */
 363
 364/* begin - purge list funcs */
 365static int debug_purgelist_print(struct dlm_ctxt *dlm, char *buf, int len)
 366{
 367        struct dlm_lock_resource *res;
 368        int out = 0;
 369        unsigned long total = 0;
 370
 371        out += snprintf(buf + out, len - out,
 372                        "Dumping Purgelist for Domain: %s\n", dlm->name);
 373
 374        spin_lock(&dlm->spinlock);
 375        list_for_each_entry(res, &dlm->purge_list, purge) {
 376                ++total;
 377                if (len - out < 100)
 378                        continue;
 379                spin_lock(&res->spinlock);
 380                out += stringify_lockname(res->lockname.name,
 381                                          res->lockname.len,
 382                                          buf + out, len - out);
 383                out += snprintf(buf + out, len - out, "\t%ld\n",
 384                                (jiffies - res->last_used)/HZ);
 385                spin_unlock(&res->spinlock);
 386        }
 387        spin_unlock(&dlm->spinlock);
 388
 389        out += snprintf(buf + out, len - out, "Total on list: %lu\n", total);
 390
 391        return out;
 392}
 393
 394static int debug_purgelist_open(struct inode *inode, struct file *file)
 395{
 396        struct dlm_ctxt *dlm = inode->i_private;
 397        char *buf = NULL;
 398
 399        buf = (char *) get_zeroed_page(GFP_NOFS);
 400        if (!buf)
 401                goto bail;
 402
 403        i_size_write(inode, debug_purgelist_print(dlm, buf, PAGE_SIZE - 1));
 404
 405        file->private_data = buf;
 406
 407        return 0;
 408bail:
 409        return -ENOMEM;
 410}
 411
 412static const struct file_operations debug_purgelist_fops = {
 413        .open =         debug_purgelist_open,
 414        .release =      debug_release,
 415        .read =         debug_read,
 416        .llseek =       generic_file_llseek,
 417};
 418/* end - purge list funcs */
 419
 420/* begin - debug mle funcs */
 421static int debug_mle_print(struct dlm_ctxt *dlm, char *buf, int len)
 422{
 423        struct dlm_master_list_entry *mle;
 424        struct hlist_head *bucket;
 425        int i, out = 0;
 426        unsigned long total = 0, longest = 0, bucket_count = 0;
 427
 428        out += snprintf(buf + out, len - out,
 429                        "Dumping MLEs for Domain: %s\n", dlm->name);
 430
 431        spin_lock(&dlm->master_lock);
 432        for (i = 0; i < DLM_HASH_BUCKETS; i++) {
 433                bucket = dlm_master_hash(dlm, i);
 434                hlist_for_each_entry(mle, bucket, master_hash_node) {
 435                        ++total;
 436                        ++bucket_count;
 437                        if (len - out < 200)
 438                                continue;
 439                        out += dump_mle(mle, buf + out, len - out);
 440                }
 441                longest = max(longest, bucket_count);
 442                bucket_count = 0;
 443        }
 444        spin_unlock(&dlm->master_lock);
 445
 446        out += snprintf(buf + out, len - out,
 447                        "Total: %lu, Longest: %lu\n", total, longest);
 448        return out;
 449}
 450
 451static int debug_mle_open(struct inode *inode, struct file *file)
 452{
 453        struct dlm_ctxt *dlm = inode->i_private;
 454        char *buf = NULL;
 455
 456        buf = (char *) get_zeroed_page(GFP_NOFS);
 457        if (!buf)
 458                goto bail;
 459
 460        i_size_write(inode, debug_mle_print(dlm, buf, PAGE_SIZE - 1));
 461
 462        file->private_data = buf;
 463
 464        return 0;
 465bail:
 466        return -ENOMEM;
 467}
 468
 469static const struct file_operations debug_mle_fops = {
 470        .open =         debug_mle_open,
 471        .release =      debug_release,
 472        .read =         debug_read,
 473        .llseek =       generic_file_llseek,
 474};
 475
 476/* end - debug mle funcs */
 477
 478/* begin - debug lockres funcs */
 479static int dump_lock(struct dlm_lock *lock, int list_type, char *buf, int len)
 480{
 481        int out;
 482
 483#define DEBUG_LOCK_VERSION      1
 484        spin_lock(&lock->spinlock);
 485        out = snprintf(buf, len, "LOCK:%d,%d,%d,%d,%d,%d:%lld,%d,%d,%d,%d,%d,"
 486                       "%d,%d,%d,%d\n",
 487                       DEBUG_LOCK_VERSION,
 488                       list_type, lock->ml.type, lock->ml.convert_type,
 489                       lock->ml.node,
 490                       dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
 491                       dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
 492                       !list_empty(&lock->ast_list),
 493                       !list_empty(&lock->bast_list),
 494                       lock->ast_pending, lock->bast_pending,
 495                       lock->convert_pending, lock->lock_pending,
 496                       lock->cancel_pending, lock->unlock_pending,
 497                       kref_read(&lock->lock_refs));
 498        spin_unlock(&lock->spinlock);
 499
 500        return out;
 501}
 502
 503static int dump_lockres(struct dlm_lock_resource *res, char *buf, int len)
 504{
 505        struct dlm_lock *lock;
 506        int i;
 507        int out = 0;
 508
 509        out += snprintf(buf + out, len - out, "NAME:");
 510        out += stringify_lockname(res->lockname.name, res->lockname.len,
 511                                  buf + out, len - out);
 512        out += snprintf(buf + out, len - out, "\n");
 513
 514#define DEBUG_LRES_VERSION      1
 515        out += snprintf(buf + out, len - out,
 516                        "LRES:%d,%d,%d,%ld,%d,%d,%d,%d,%d,%d,%d\n",
 517                        DEBUG_LRES_VERSION,
 518                        res->owner, res->state, res->last_used,
 519                        !list_empty(&res->purge),
 520                        !list_empty(&res->dirty),
 521                        !list_empty(&res->recovering),
 522                        res->inflight_locks, res->migration_pending,
 523                        atomic_read(&res->asts_reserved),
 524                        kref_read(&res->refs));
 525
 526        /* refmap */
 527        out += snprintf(buf + out, len - out, "RMAP:");
 528        out += stringify_nodemap(res->refmap, O2NM_MAX_NODES,
 529                                 buf + out, len - out);
 530        out += snprintf(buf + out, len - out, "\n");
 531
 532        /* lvb */
 533        out += snprintf(buf + out, len - out, "LVBX:");
 534        for (i = 0; i < DLM_LVB_LEN; i++)
 535                out += snprintf(buf + out, len - out,
 536                                        "%02x", (unsigned char)res->lvb[i]);
 537        out += snprintf(buf + out, len - out, "\n");
 538
 539        /* granted */
 540        list_for_each_entry(lock, &res->granted, list)
 541                out += dump_lock(lock, 0, buf + out, len - out);
 542
 543        /* converting */
 544        list_for_each_entry(lock, &res->converting, list)
 545                out += dump_lock(lock, 1, buf + out, len - out);
 546
 547        /* blocked */
 548        list_for_each_entry(lock, &res->blocked, list)
 549                out += dump_lock(lock, 2, buf + out, len - out);
 550
 551        out += snprintf(buf + out, len - out, "\n");
 552
 553        return out;
 554}
 555
 556static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
 557{
 558        struct debug_lockres *dl = m->private;
 559        struct dlm_ctxt *dlm = dl->dl_ctxt;
 560        struct dlm_lock_resource *oldres = dl->dl_res;
 561        struct dlm_lock_resource *res = NULL;
 562        struct list_head *track_list;
 563
 564        spin_lock(&dlm->track_lock);
 565        if (oldres)
 566                track_list = &oldres->tracking;
 567        else {
 568                track_list = &dlm->tracking_list;
 569                if (list_empty(track_list)) {
 570                        dl = NULL;
 571                        spin_unlock(&dlm->track_lock);
 572                        goto bail;
 573                }
 574        }
 575
 576        list_for_each_entry(res, track_list, tracking) {
 577                if (&res->tracking == &dlm->tracking_list)
 578                        res = NULL;
 579                else
 580                        dlm_lockres_get(res);
 581                break;
 582        }
 583        spin_unlock(&dlm->track_lock);
 584
 585        if (oldres)
 586                dlm_lockres_put(oldres);
 587
 588        dl->dl_res = res;
 589
 590        if (res) {
 591                spin_lock(&res->spinlock);
 592                dump_lockres(res, dl->dl_buf, dl->dl_len - 1);
 593                spin_unlock(&res->spinlock);
 594        } else
 595                dl = NULL;
 596
 597bail:
 598        /* passed to seq_show */
 599        return dl;
 600}
 601
 602static void lockres_seq_stop(struct seq_file *m, void *v)
 603{
 604}
 605
 606static void *lockres_seq_next(struct seq_file *m, void *v, loff_t *pos)
 607{
 608        return NULL;
 609}
 610
 611static int lockres_seq_show(struct seq_file *s, void *v)
 612{
 613        struct debug_lockres *dl = (struct debug_lockres *)v;
 614
 615        seq_printf(s, "%s", dl->dl_buf);
 616
 617        return 0;
 618}
 619
 620static const struct seq_operations debug_lockres_ops = {
 621        .start =        lockres_seq_start,
 622        .stop =         lockres_seq_stop,
 623        .next =         lockres_seq_next,
 624        .show =         lockres_seq_show,
 625};
 626
 627static int debug_lockres_open(struct inode *inode, struct file *file)
 628{
 629        struct dlm_ctxt *dlm = inode->i_private;
 630        struct debug_lockres *dl;
 631        void *buf;
 632
 633        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 634        if (!buf)
 635                goto bail;
 636
 637        dl = __seq_open_private(file, &debug_lockres_ops, sizeof(*dl));
 638        if (!dl)
 639                goto bailfree;
 640
 641        dl->dl_len = PAGE_SIZE;
 642        dl->dl_buf = buf;
 643
 644        dlm_grab(dlm);
 645        dl->dl_ctxt = dlm;
 646
 647        return 0;
 648
 649bailfree:
 650        kfree(buf);
 651bail:
 652        mlog_errno(-ENOMEM);
 653        return -ENOMEM;
 654}
 655
 656static int debug_lockres_release(struct inode *inode, struct file *file)
 657{
 658        struct seq_file *seq = file->private_data;
 659        struct debug_lockres *dl = (struct debug_lockres *)seq->private;
 660
 661        if (dl->dl_res)
 662                dlm_lockres_put(dl->dl_res);
 663        dlm_put(dl->dl_ctxt);
 664        kfree(dl->dl_buf);
 665        return seq_release_private(inode, file);
 666}
 667
 668static const struct file_operations debug_lockres_fops = {
 669        .open =         debug_lockres_open,
 670        .release =      debug_lockres_release,
 671        .read =         seq_read,
 672        .llseek =       seq_lseek,
 673};
 674/* end - debug lockres funcs */
 675
 676/* begin - debug state funcs */
 677static int debug_state_print(struct dlm_ctxt *dlm, char *buf, int len)
 678{
 679        int out = 0;
 680        struct dlm_reco_node_data *node;
 681        char *state;
 682        int cur_mles = 0, tot_mles = 0;
 683        int i;
 684
 685        spin_lock(&dlm->spinlock);
 686
 687        switch (dlm->dlm_state) {
 688        case DLM_CTXT_NEW:
 689                state = "NEW"; break;
 690        case DLM_CTXT_JOINED:
 691                state = "JOINED"; break;
 692        case DLM_CTXT_IN_SHUTDOWN:
 693                state = "SHUTDOWN"; break;
 694        case DLM_CTXT_LEAVING:
 695                state = "LEAVING"; break;
 696        default:
 697                state = "UNKNOWN"; break;
 698        }
 699
 700        /* Domain: xxxxxxxxxx  Key: 0xdfbac769 */
 701        out += snprintf(buf + out, len - out,
 702                        "Domain: %s  Key: 0x%08x  Protocol: %d.%d\n",
 703                        dlm->name, dlm->key, dlm->dlm_locking_proto.pv_major,
 704                        dlm->dlm_locking_proto.pv_minor);
 705
 706        /* Thread Pid: xxx  Node: xxx  State: xxxxx */
 707        out += snprintf(buf + out, len - out,
 708                        "Thread Pid: %d  Node: %d  State: %s\n",
 709                        task_pid_nr(dlm->dlm_thread_task), dlm->node_num, state);
 710
 711        /* Number of Joins: xxx  Joining Node: xxx */
 712        out += snprintf(buf + out, len - out,
 713                        "Number of Joins: %d  Joining Node: %d\n",
 714                        dlm->num_joins, dlm->joining_node);
 715
 716        /* Domain Map: xx xx xx */
 717        out += snprintf(buf + out, len - out, "Domain Map: ");
 718        out += stringify_nodemap(dlm->domain_map, O2NM_MAX_NODES,
 719                                 buf + out, len - out);
 720        out += snprintf(buf + out, len - out, "\n");
 721
 722        /* Exit Domain Map: xx xx xx */
 723        out += snprintf(buf + out, len - out, "Exit Domain Map: ");
 724        out += stringify_nodemap(dlm->exit_domain_map, O2NM_MAX_NODES,
 725                                 buf + out, len - out);
 726        out += snprintf(buf + out, len - out, "\n");
 727
 728        /* Live Map: xx xx xx */
 729        out += snprintf(buf + out, len - out, "Live Map: ");
 730        out += stringify_nodemap(dlm->live_nodes_map, O2NM_MAX_NODES,
 731                                 buf + out, len - out);
 732        out += snprintf(buf + out, len - out, "\n");
 733
 734        /* Lock Resources: xxx (xxx) */
 735        out += snprintf(buf + out, len - out,
 736                        "Lock Resources: %d (%d)\n",
 737                        atomic_read(&dlm->res_cur_count),
 738                        atomic_read(&dlm->res_tot_count));
 739
 740        for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
 741                tot_mles += atomic_read(&dlm->mle_tot_count[i]);
 742
 743        for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
 744                cur_mles += atomic_read(&dlm->mle_cur_count[i]);
 745
 746        /* MLEs: xxx (xxx) */
 747        out += snprintf(buf + out, len - out,
 748                        "MLEs: %d (%d)\n", cur_mles, tot_mles);
 749
 750        /*  Blocking: xxx (xxx) */
 751        out += snprintf(buf + out, len - out,
 752                        "  Blocking: %d (%d)\n",
 753                        atomic_read(&dlm->mle_cur_count[DLM_MLE_BLOCK]),
 754                        atomic_read(&dlm->mle_tot_count[DLM_MLE_BLOCK]));
 755
 756        /*  Mastery: xxx (xxx) */
 757        out += snprintf(buf + out, len - out,
 758                        "  Mastery: %d (%d)\n",
 759                        atomic_read(&dlm->mle_cur_count[DLM_MLE_MASTER]),
 760                        atomic_read(&dlm->mle_tot_count[DLM_MLE_MASTER]));
 761
 762        /*  Migration: xxx (xxx) */
 763        out += snprintf(buf + out, len - out,
 764                        "  Migration: %d (%d)\n",
 765                        atomic_read(&dlm->mle_cur_count[DLM_MLE_MIGRATION]),
 766                        atomic_read(&dlm->mle_tot_count[DLM_MLE_MIGRATION]));
 767
 768        /* Lists: Dirty=Empty  Purge=InUse  PendingASTs=Empty  ... */
 769        out += snprintf(buf + out, len - out,
 770                        "Lists: Dirty=%s  Purge=%s  PendingASTs=%s  "
 771                        "PendingBASTs=%s\n",
 772                        (list_empty(&dlm->dirty_list) ? "Empty" : "InUse"),
 773                        (list_empty(&dlm->purge_list) ? "Empty" : "InUse"),
 774                        (list_empty(&dlm->pending_asts) ? "Empty" : "InUse"),
 775                        (list_empty(&dlm->pending_basts) ? "Empty" : "InUse"));
 776
 777        /* Purge Count: xxx  Refs: xxx */
 778        out += snprintf(buf + out, len - out,
 779                        "Purge Count: %d  Refs: %d\n", dlm->purge_count,
 780                        kref_read(&dlm->dlm_refs));
 781
 782        /* Dead Node: xxx */
 783        out += snprintf(buf + out, len - out,
 784                        "Dead Node: %d\n", dlm->reco.dead_node);
 785
 786        /* What about DLM_RECO_STATE_FINALIZE? */
 787        if (dlm->reco.state == DLM_RECO_STATE_ACTIVE)
 788                state = "ACTIVE";
 789        else
 790                state = "INACTIVE";
 791
 792        /* Recovery Pid: xxxx  Master: xxx  State: xxxx */
 793        out += snprintf(buf + out, len - out,
 794                        "Recovery Pid: %d  Master: %d  State: %s\n",
 795                        task_pid_nr(dlm->dlm_reco_thread_task),
 796                        dlm->reco.new_master, state);
 797
 798        /* Recovery Map: xx xx */
 799        out += snprintf(buf + out, len - out, "Recovery Map: ");
 800        out += stringify_nodemap(dlm->recovery_map, O2NM_MAX_NODES,
 801                                 buf + out, len - out);
 802        out += snprintf(buf + out, len - out, "\n");
 803
 804        /* Recovery Node State: */
 805        out += snprintf(buf + out, len - out, "Recovery Node State:\n");
 806        list_for_each_entry(node, &dlm->reco.node_data, list) {
 807                switch (node->state) {
 808                case DLM_RECO_NODE_DATA_INIT:
 809                        state = "INIT";
 810                        break;
 811                case DLM_RECO_NODE_DATA_REQUESTING:
 812                        state = "REQUESTING";
 813                        break;
 814                case DLM_RECO_NODE_DATA_DEAD:
 815                        state = "DEAD";
 816                        break;
 817                case DLM_RECO_NODE_DATA_RECEIVING:
 818                        state = "RECEIVING";
 819                        break;
 820                case DLM_RECO_NODE_DATA_REQUESTED:
 821                        state = "REQUESTED";
 822                        break;
 823                case DLM_RECO_NODE_DATA_DONE:
 824                        state = "DONE";
 825                        break;
 826                case DLM_RECO_NODE_DATA_FINALIZE_SENT:
 827                        state = "FINALIZE-SENT";
 828                        break;
 829                default:
 830                        state = "BAD";
 831                        break;
 832                }
 833                out += snprintf(buf + out, len - out, "\t%u - %s\n",
 834                                node->node_num, state);
 835        }
 836
 837        spin_unlock(&dlm->spinlock);
 838
 839        return out;
 840}
 841
 842static int debug_state_open(struct inode *inode, struct file *file)
 843{
 844        struct dlm_ctxt *dlm = inode->i_private;
 845        char *buf = NULL;
 846
 847        buf = (char *) get_zeroed_page(GFP_NOFS);
 848        if (!buf)
 849                goto bail;
 850
 851        i_size_write(inode, debug_state_print(dlm, buf, PAGE_SIZE - 1));
 852
 853        file->private_data = buf;
 854
 855        return 0;
 856bail:
 857        return -ENOMEM;
 858}
 859
 860static const struct file_operations debug_state_fops = {
 861        .open =         debug_state_open,
 862        .release =      debug_release,
 863        .read =         debug_read,
 864        .llseek =       generic_file_llseek,
 865};
 866/* end  - debug state funcs */
 867
 868/* files in subroot */
 869int dlm_debug_init(struct dlm_ctxt *dlm)
 870{
 871        struct dlm_debug_ctxt *dc = dlm->dlm_debug_ctxt;
 872
 873        /* for dumping dlm_ctxt */
 874        dc->debug_state_dentry = debugfs_create_file(DLM_DEBUGFS_DLM_STATE,
 875                                                     S_IFREG|S_IRUSR,
 876                                                     dlm->dlm_debugfs_subroot,
 877                                                     dlm, &debug_state_fops);
 878        if (!dc->debug_state_dentry) {
 879                mlog_errno(-ENOMEM);
 880                goto bail;
 881        }
 882
 883        /* for dumping lockres */
 884        dc->debug_lockres_dentry =
 885                        debugfs_create_file(DLM_DEBUGFS_LOCKING_STATE,
 886                                            S_IFREG|S_IRUSR,
 887                                            dlm->dlm_debugfs_subroot,
 888                                            dlm, &debug_lockres_fops);
 889        if (!dc->debug_lockres_dentry) {
 890                mlog_errno(-ENOMEM);
 891                goto bail;
 892        }
 893
 894        /* for dumping mles */
 895        dc->debug_mle_dentry = debugfs_create_file(DLM_DEBUGFS_MLE_STATE,
 896                                                   S_IFREG|S_IRUSR,
 897                                                   dlm->dlm_debugfs_subroot,
 898                                                   dlm, &debug_mle_fops);
 899        if (!dc->debug_mle_dentry) {
 900                mlog_errno(-ENOMEM);
 901                goto bail;
 902        }
 903
 904        /* for dumping lockres on the purge list */
 905        dc->debug_purgelist_dentry =
 906                        debugfs_create_file(DLM_DEBUGFS_PURGE_LIST,
 907                                            S_IFREG|S_IRUSR,
 908                                            dlm->dlm_debugfs_subroot,
 909                                            dlm, &debug_purgelist_fops);
 910        if (!dc->debug_purgelist_dentry) {
 911                mlog_errno(-ENOMEM);
 912                goto bail;
 913        }
 914
 915        return 0;
 916
 917bail:
 918        return -ENOMEM;
 919}
 920
 921void dlm_debug_shutdown(struct dlm_ctxt *dlm)
 922{
 923        struct dlm_debug_ctxt *dc = dlm->dlm_debug_ctxt;
 924
 925        if (dc) {
 926                debugfs_remove(dc->debug_purgelist_dentry);
 927                debugfs_remove(dc->debug_mle_dentry);
 928                debugfs_remove(dc->debug_lockres_dentry);
 929                debugfs_remove(dc->debug_state_dentry);
 930                kfree(dc);
 931                dc = NULL;
 932        }
 933}
 934
 935/* subroot - domain dir */
 936int dlm_create_debugfs_subroot(struct dlm_ctxt *dlm)
 937{
 938        dlm->dlm_debugfs_subroot = debugfs_create_dir(dlm->name,
 939                                                      dlm_debugfs_root);
 940        if (!dlm->dlm_debugfs_subroot) {
 941                mlog_errno(-ENOMEM);
 942                goto bail;
 943        }
 944
 945        dlm->dlm_debug_ctxt = kzalloc(sizeof(struct dlm_debug_ctxt),
 946                                      GFP_KERNEL);
 947        if (!dlm->dlm_debug_ctxt) {
 948                mlog_errno(-ENOMEM);
 949                goto bail;
 950        }
 951
 952        return 0;
 953bail:
 954        dlm_destroy_debugfs_subroot(dlm);
 955        return -ENOMEM;
 956}
 957
 958void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm)
 959{
 960        debugfs_remove(dlm->dlm_debugfs_subroot);
 961}
 962
 963/* debugfs root */
 964int dlm_create_debugfs_root(void)
 965{
 966        dlm_debugfs_root = debugfs_create_dir(DLM_DEBUGFS_DIR, NULL);
 967        if (!dlm_debugfs_root) {
 968                mlog_errno(-ENOMEM);
 969                return -ENOMEM;
 970        }
 971        return 0;
 972}
 973
 974void dlm_destroy_debugfs_root(void)
 975{
 976        debugfs_remove(dlm_debugfs_root);
 977}
 978#endif  /* CONFIG_DEBUG_FS */
 979