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