Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * dlmdebug.c
0004  *
0005  * debug functionality for the dlm
0006  *
0007  * Copyright (C) 2004, 2008 Oracle.  All rights reserved.
0008  */
0009 
0010 #include <linux/types.h>
0011 #include <linux/slab.h>
0012 #include <linux/highmem.h>
0013 #include <linux/sysctl.h>
0014 #include <linux/spinlock.h>
0015 #include <linux/debugfs.h>
0016 #include <linux/export.h>
0017 
0018 #include "../cluster/heartbeat.h"
0019 #include "../cluster/nodemanager.h"
0020 #include "../cluster/tcp.h"
0021 
0022 #include "dlmapi.h"
0023 #include "dlmcommon.h"
0024 #include "dlmdomain.h"
0025 #include "dlmdebug.h"
0026 
0027 #define MLOG_MASK_PREFIX ML_DLM
0028 #include "../cluster/masklog.h"
0029 
0030 static int stringify_lockname(const char *lockname, int locklen, char *buf,
0031                   int len);
0032 
0033 void dlm_print_one_lock_resource(struct dlm_lock_resource *res)
0034 {
0035     spin_lock(&res->spinlock);
0036     __dlm_print_one_lock_resource(res);
0037     spin_unlock(&res->spinlock);
0038 }
0039 
0040 static void dlm_print_lockres_refmap(struct dlm_lock_resource *res)
0041 {
0042     int bit;
0043     assert_spin_locked(&res->spinlock);
0044 
0045     printk("  refmap nodes: [ ");
0046     bit = 0;
0047     while (1) {
0048         bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit);
0049         if (bit >= O2NM_MAX_NODES)
0050             break;
0051         printk("%u ", bit);
0052         bit++;
0053     }
0054     printk("], inflight=%u\n", res->inflight_locks);
0055 }
0056 
0057 static void __dlm_print_lock(struct dlm_lock *lock)
0058 {
0059     spin_lock(&lock->spinlock);
0060 
0061     printk("    type=%d, conv=%d, node=%u, cookie=%u:%llu, "
0062            "ref=%u, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c), "
0063            "pending=(conv=%c,lock=%c,cancel=%c,unlock=%c)\n",
0064            lock->ml.type, lock->ml.convert_type, lock->ml.node,
0065            dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
0066            dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
0067            kref_read(&lock->lock_refs),
0068            (list_empty(&lock->ast_list) ? 'y' : 'n'),
0069            (lock->ast_pending ? 'y' : 'n'),
0070            (list_empty(&lock->bast_list) ? 'y' : 'n'),
0071            (lock->bast_pending ? 'y' : 'n'),
0072            (lock->convert_pending ? 'y' : 'n'),
0073            (lock->lock_pending ? 'y' : 'n'),
0074            (lock->cancel_pending ? 'y' : 'n'),
0075            (lock->unlock_pending ? 'y' : 'n'));
0076 
0077     spin_unlock(&lock->spinlock);
0078 }
0079 
0080 void __dlm_print_one_lock_resource(struct dlm_lock_resource *res)
0081 {
0082     struct dlm_lock *lock;
0083     char buf[DLM_LOCKID_NAME_MAX];
0084 
0085     assert_spin_locked(&res->spinlock);
0086 
0087     stringify_lockname(res->lockname.name, res->lockname.len,
0088                buf, sizeof(buf));
0089     printk("lockres: %s, owner=%u, state=%u\n",
0090            buf, res->owner, res->state);
0091     printk("  last used: %lu, refcnt: %u, on purge list: %s\n",
0092            res->last_used, kref_read(&res->refs),
0093            list_empty(&res->purge) ? "no" : "yes");
0094     printk("  on dirty list: %s, on reco list: %s, "
0095            "migrating pending: %s\n",
0096            list_empty(&res->dirty) ? "no" : "yes",
0097            list_empty(&res->recovering) ? "no" : "yes",
0098            res->migration_pending ? "yes" : "no");
0099     printk("  inflight locks: %d, asts reserved: %d\n",
0100            res->inflight_locks, atomic_read(&res->asts_reserved));
0101     dlm_print_lockres_refmap(res);
0102     printk("  granted queue:\n");
0103     list_for_each_entry(lock, &res->granted, list) {
0104         __dlm_print_lock(lock);
0105     }
0106     printk("  converting queue:\n");
0107     list_for_each_entry(lock, &res->converting, list) {
0108         __dlm_print_lock(lock);
0109     }
0110     printk("  blocked queue:\n");
0111     list_for_each_entry(lock, &res->blocked, list) {
0112         __dlm_print_lock(lock);
0113     }
0114 }
0115 
0116 void dlm_print_one_lock(struct dlm_lock *lockid)
0117 {
0118     dlm_print_one_lock_resource(lockid->lockres);
0119 }
0120 EXPORT_SYMBOL_GPL(dlm_print_one_lock);
0121 
0122 static const char *dlm_errnames[] = {
0123     [DLM_NORMAL] =          "DLM_NORMAL",
0124     [DLM_GRANTED] =         "DLM_GRANTED",
0125     [DLM_DENIED] =          "DLM_DENIED",
0126     [DLM_DENIED_NOLOCKS] =      "DLM_DENIED_NOLOCKS",
0127     [DLM_WORKING] =         "DLM_WORKING",
0128     [DLM_BLOCKED] =         "DLM_BLOCKED",
0129     [DLM_BLOCKED_ORPHAN] =      "DLM_BLOCKED_ORPHAN",
0130     [DLM_DENIED_GRACE_PERIOD] = "DLM_DENIED_GRACE_PERIOD",
0131     [DLM_SYSERR] =          "DLM_SYSERR",
0132     [DLM_NOSUPPORT] =       "DLM_NOSUPPORT",
0133     [DLM_CANCELGRANT] =     "DLM_CANCELGRANT",
0134     [DLM_IVLOCKID] =        "DLM_IVLOCKID",
0135     [DLM_SYNC] =            "DLM_SYNC",
0136     [DLM_BADTYPE] =         "DLM_BADTYPE",
0137     [DLM_BADRESOURCE] =     "DLM_BADRESOURCE",
0138     [DLM_MAXHANDLES] =      "DLM_MAXHANDLES",
0139     [DLM_NOCLINFO] =        "DLM_NOCLINFO",
0140     [DLM_NOLOCKMGR] =       "DLM_NOLOCKMGR",
0141     [DLM_NOPURGED] =        "DLM_NOPURGED",
0142     [DLM_BADARGS] =         "DLM_BADARGS",
0143     [DLM_VOID] =            "DLM_VOID",
0144     [DLM_NOTQUEUED] =       "DLM_NOTQUEUED",
0145     [DLM_IVBUFLEN] =        "DLM_IVBUFLEN",
0146     [DLM_CVTUNGRANT] =      "DLM_CVTUNGRANT",
0147     [DLM_BADPARAM] =        "DLM_BADPARAM",
0148     [DLM_VALNOTVALID] =     "DLM_VALNOTVALID",
0149     [DLM_REJECTED] =        "DLM_REJECTED",
0150     [DLM_ABORT] =           "DLM_ABORT",
0151     [DLM_CANCEL] =          "DLM_CANCEL",
0152     [DLM_IVRESHANDLE] =     "DLM_IVRESHANDLE",
0153     [DLM_DEADLOCK] =        "DLM_DEADLOCK",
0154     [DLM_DENIED_NOASTS] =       "DLM_DENIED_NOASTS",
0155     [DLM_FORWARD] =         "DLM_FORWARD",
0156     [DLM_TIMEOUT] =         "DLM_TIMEOUT",
0157     [DLM_IVGROUPID] =       "DLM_IVGROUPID",
0158     [DLM_VERS_CONFLICT] =       "DLM_VERS_CONFLICT",
0159     [DLM_BAD_DEVICE_PATH] =     "DLM_BAD_DEVICE_PATH",
0160     [DLM_NO_DEVICE_PERMISSION] =    "DLM_NO_DEVICE_PERMISSION",
0161     [DLM_NO_CONTROL_DEVICE ] =  "DLM_NO_CONTROL_DEVICE ",
0162     [DLM_RECOVERING] =      "DLM_RECOVERING",
0163     [DLM_MIGRATING] =       "DLM_MIGRATING",
0164     [DLM_MAXSTATS] =        "DLM_MAXSTATS",
0165 };
0166 
0167 static const char *dlm_errmsgs[] = {
0168     [DLM_NORMAL] =          "request in progress",
0169     [DLM_GRANTED] =         "request granted",
0170     [DLM_DENIED] =          "request denied",
0171     [DLM_DENIED_NOLOCKS] =      "request denied, out of system resources",
0172     [DLM_WORKING] =         "async request in progress",
0173     [DLM_BLOCKED] =         "lock request blocked",
0174     [DLM_BLOCKED_ORPHAN] =      "lock request blocked by a orphan lock",
0175     [DLM_DENIED_GRACE_PERIOD] =     "topological change in progress",
0176     [DLM_SYSERR] =          "system error",
0177     [DLM_NOSUPPORT] =       "unsupported",
0178     [DLM_CANCELGRANT] =         "can't cancel convert: already granted",
0179     [DLM_IVLOCKID] =        "bad lockid",
0180     [DLM_SYNC] =            "synchronous request granted",
0181     [DLM_BADTYPE] =         "bad resource type",
0182     [DLM_BADRESOURCE] =         "bad resource handle",
0183     [DLM_MAXHANDLES] =      "no more resource handles",
0184     [DLM_NOCLINFO] =        "can't contact cluster manager",
0185     [DLM_NOLOCKMGR] =       "can't contact lock manager",
0186     [DLM_NOPURGED] =        "can't contact purge daemon",
0187     [DLM_BADARGS] =         "bad api args",
0188     [DLM_VOID] =            "no status",
0189     [DLM_NOTQUEUED] =       "NOQUEUE was specified and request failed",
0190     [DLM_IVBUFLEN] =        "invalid resource name length",
0191     [DLM_CVTUNGRANT] =      "attempted to convert ungranted lock",
0192     [DLM_BADPARAM] =        "invalid lock mode specified",
0193     [DLM_VALNOTVALID] =         "value block has been invalidated",
0194     [DLM_REJECTED] =        "request rejected, unrecognized client",
0195     [DLM_ABORT] =           "blocked lock request cancelled",
0196     [DLM_CANCEL] =          "conversion request cancelled",
0197     [DLM_IVRESHANDLE] =         "invalid resource handle",
0198     [DLM_DEADLOCK] =        "deadlock recovery refused this request",
0199     [DLM_DENIED_NOASTS] =       "failed to allocate AST",
0200     [DLM_FORWARD] =         "request must wait for primary's response",
0201     [DLM_TIMEOUT] =         "timeout value for lock has expired",
0202     [DLM_IVGROUPID] =       "invalid group specification",
0203     [DLM_VERS_CONFLICT] =       "version conflicts prevent request handling",
0204     [DLM_BAD_DEVICE_PATH] =     "Locks device does not exist or path wrong",
0205     [DLM_NO_DEVICE_PERMISSION] =    "Client has insufficient perms for device",
0206     [DLM_NO_CONTROL_DEVICE] =   "Cannot set options on opened device ",
0207     [DLM_RECOVERING] =      "lock resource being recovered",
0208     [DLM_MIGRATING] =       "lock resource being migrated",
0209     [DLM_MAXSTATS] =        "invalid error number",
0210 };
0211 
0212 const char *dlm_errmsg(enum dlm_status err)
0213 {
0214     if (err >= DLM_MAXSTATS || err < 0)
0215         return dlm_errmsgs[DLM_MAXSTATS];
0216     return dlm_errmsgs[err];
0217 }
0218 EXPORT_SYMBOL_GPL(dlm_errmsg);
0219 
0220 const char *dlm_errname(enum dlm_status err)
0221 {
0222     if (err >= DLM_MAXSTATS || err < 0)
0223         return dlm_errnames[DLM_MAXSTATS];
0224     return dlm_errnames[err];
0225 }
0226 EXPORT_SYMBOL_GPL(dlm_errname);
0227 
0228 /* NOTE: This function converts a lockname into a string. It uses knowledge
0229  * of the format of the lockname that should be outside the purview of the dlm.
0230  * We are adding only to make dlm debugging slightly easier.
0231  *
0232  * For more on lockname formats, please refer to dlmglue.c and ocfs2_lockid.h.
0233  */
0234 static int stringify_lockname(const char *lockname, int locklen, char *buf,
0235                   int len)
0236 {
0237     int out = 0;
0238     __be64 inode_blkno_be;
0239 
0240 #define OCFS2_DENTRY_LOCK_INO_START 18
0241     if (*lockname == 'N') {
0242         memcpy((__be64 *)&inode_blkno_be,
0243                (char *)&lockname[OCFS2_DENTRY_LOCK_INO_START],
0244                sizeof(__be64));
0245         out += scnprintf(buf + out, len - out, "%.*s%08x",
0246                 OCFS2_DENTRY_LOCK_INO_START - 1, lockname,
0247                 (unsigned int)be64_to_cpu(inode_blkno_be));
0248     } else
0249         out += scnprintf(buf + out, len - out, "%.*s",
0250                 locklen, lockname);
0251     return out;
0252 }
0253 
0254 static int stringify_nodemap(unsigned long *nodemap, int maxnodes,
0255                  char *buf, int len)
0256 {
0257     int out = 0;
0258     int i = -1;
0259 
0260     while ((i = find_next_bit(nodemap, maxnodes, i + 1)) < maxnodes)
0261         out += scnprintf(buf + out, len - out, "%d ", i);
0262 
0263     return out;
0264 }
0265 
0266 static int dump_mle(struct dlm_master_list_entry *mle, char *buf, int len)
0267 {
0268     int out = 0;
0269     char *mle_type;
0270 
0271     if (mle->type == DLM_MLE_BLOCK)
0272         mle_type = "BLK";
0273     else if (mle->type == DLM_MLE_MASTER)
0274         mle_type = "MAS";
0275     else
0276         mle_type = "MIG";
0277 
0278     out += stringify_lockname(mle->mname, mle->mnamelen, buf + out, len - out);
0279     out += scnprintf(buf + out, len - out,
0280             "\t%3s\tmas=%3u\tnew=%3u\tevt=%1d\tuse=%1d\tref=%3d\n",
0281             mle_type, mle->master, mle->new_master,
0282             !list_empty(&mle->hb_events),
0283             !!mle->inuse,
0284             kref_read(&mle->mle_refs));
0285 
0286     out += scnprintf(buf + out, len - out, "Maybe=");
0287     out += stringify_nodemap(mle->maybe_map, O2NM_MAX_NODES,
0288                  buf + out, len - out);
0289     out += scnprintf(buf + out, len - out, "\n");
0290 
0291     out += scnprintf(buf + out, len - out, "Vote=");
0292     out += stringify_nodemap(mle->vote_map, O2NM_MAX_NODES,
0293                  buf + out, len - out);
0294     out += scnprintf(buf + out, len - out, "\n");
0295 
0296     out += scnprintf(buf + out, len - out, "Response=");
0297     out += stringify_nodemap(mle->response_map, O2NM_MAX_NODES,
0298                  buf + out, len - out);
0299     out += scnprintf(buf + out, len - out, "\n");
0300 
0301     out += scnprintf(buf + out, len - out, "Node=");
0302     out += stringify_nodemap(mle->node_map, O2NM_MAX_NODES,
0303                  buf + out, len - out);
0304     out += scnprintf(buf + out, len - out, "\n");
0305 
0306     out += scnprintf(buf + out, len - out, "\n");
0307 
0308     return out;
0309 }
0310 
0311 void dlm_print_one_mle(struct dlm_master_list_entry *mle)
0312 {
0313     char *buf;
0314 
0315     buf = (char *) get_zeroed_page(GFP_ATOMIC);
0316     if (buf) {
0317         dump_mle(mle, buf, PAGE_SIZE - 1);
0318         free_page((unsigned long)buf);
0319     }
0320 }
0321 
0322 #ifdef CONFIG_DEBUG_FS
0323 
0324 static struct dentry *dlm_debugfs_root;
0325 
0326 #define DLM_DEBUGFS_DIR             "o2dlm"
0327 #define DLM_DEBUGFS_DLM_STATE           "dlm_state"
0328 #define DLM_DEBUGFS_LOCKING_STATE       "locking_state"
0329 #define DLM_DEBUGFS_MLE_STATE           "mle_state"
0330 #define DLM_DEBUGFS_PURGE_LIST          "purge_list"
0331 
0332 /* begin - utils funcs */
0333 static int debug_release(struct inode *inode, struct file *file)
0334 {
0335     free_page((unsigned long)file->private_data);
0336     return 0;
0337 }
0338 
0339 static ssize_t debug_read(struct file *file, char __user *buf,
0340               size_t nbytes, loff_t *ppos)
0341 {
0342     return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
0343                        i_size_read(file->f_mapping->host));
0344 }
0345 /* end - util funcs */
0346 
0347 /* begin - purge list funcs */
0348 static int debug_purgelist_print(struct dlm_ctxt *dlm, char *buf, int len)
0349 {
0350     struct dlm_lock_resource *res;
0351     int out = 0;
0352     unsigned long total = 0;
0353 
0354     out += scnprintf(buf + out, len - out,
0355             "Dumping Purgelist for Domain: %s\n", dlm->name);
0356 
0357     spin_lock(&dlm->spinlock);
0358     list_for_each_entry(res, &dlm->purge_list, purge) {
0359         ++total;
0360         if (len - out < 100)
0361             continue;
0362         spin_lock(&res->spinlock);
0363         out += stringify_lockname(res->lockname.name,
0364                       res->lockname.len,
0365                       buf + out, len - out);
0366         out += scnprintf(buf + out, len - out, "\t%ld\n",
0367                 (jiffies - res->last_used)/HZ);
0368         spin_unlock(&res->spinlock);
0369     }
0370     spin_unlock(&dlm->spinlock);
0371 
0372     out += scnprintf(buf + out, len - out, "Total on list: %lu\n", total);
0373 
0374     return out;
0375 }
0376 
0377 static int debug_purgelist_open(struct inode *inode, struct file *file)
0378 {
0379     struct dlm_ctxt *dlm = inode->i_private;
0380     char *buf = NULL;
0381 
0382     buf = (char *) get_zeroed_page(GFP_NOFS);
0383     if (!buf)
0384         goto bail;
0385 
0386     i_size_write(inode, debug_purgelist_print(dlm, buf, PAGE_SIZE - 1));
0387 
0388     file->private_data = buf;
0389 
0390     return 0;
0391 bail:
0392     return -ENOMEM;
0393 }
0394 
0395 static const struct file_operations debug_purgelist_fops = {
0396     .open =     debug_purgelist_open,
0397     .release =  debug_release,
0398     .read =     debug_read,
0399     .llseek =   generic_file_llseek,
0400 };
0401 /* end - purge list funcs */
0402 
0403 /* begin - debug mle funcs */
0404 static int debug_mle_print(struct dlm_ctxt *dlm, char *buf, int len)
0405 {
0406     struct dlm_master_list_entry *mle;
0407     struct hlist_head *bucket;
0408     int i, out = 0;
0409     unsigned long total = 0, longest = 0, bucket_count = 0;
0410 
0411     out += scnprintf(buf + out, len - out,
0412             "Dumping MLEs for Domain: %s\n", dlm->name);
0413 
0414     spin_lock(&dlm->master_lock);
0415     for (i = 0; i < DLM_HASH_BUCKETS; i++) {
0416         bucket = dlm_master_hash(dlm, i);
0417         hlist_for_each_entry(mle, bucket, master_hash_node) {
0418             ++total;
0419             ++bucket_count;
0420             if (len - out < 200)
0421                 continue;
0422             out += dump_mle(mle, buf + out, len - out);
0423         }
0424         longest = max(longest, bucket_count);
0425         bucket_count = 0;
0426     }
0427     spin_unlock(&dlm->master_lock);
0428 
0429     out += scnprintf(buf + out, len - out,
0430             "Total: %lu, Longest: %lu\n", total, longest);
0431     return out;
0432 }
0433 
0434 static int debug_mle_open(struct inode *inode, struct file *file)
0435 {
0436     struct dlm_ctxt *dlm = inode->i_private;
0437     char *buf = NULL;
0438 
0439     buf = (char *) get_zeroed_page(GFP_NOFS);
0440     if (!buf)
0441         goto bail;
0442 
0443     i_size_write(inode, debug_mle_print(dlm, buf, PAGE_SIZE - 1));
0444 
0445     file->private_data = buf;
0446 
0447     return 0;
0448 bail:
0449     return -ENOMEM;
0450 }
0451 
0452 static const struct file_operations debug_mle_fops = {
0453     .open =     debug_mle_open,
0454     .release =  debug_release,
0455     .read =     debug_read,
0456     .llseek =   generic_file_llseek,
0457 };
0458 
0459 /* end - debug mle funcs */
0460 
0461 /* begin - debug lockres funcs */
0462 static int dump_lock(struct dlm_lock *lock, int list_type, char *buf, int len)
0463 {
0464     int out;
0465 
0466 #define DEBUG_LOCK_VERSION  1
0467     spin_lock(&lock->spinlock);
0468     out = scnprintf(buf, len, "LOCK:%d,%d,%d,%d,%d,%d:%lld,%d,%d,%d,%d,%d,"
0469                "%d,%d,%d,%d\n",
0470                DEBUG_LOCK_VERSION,
0471                list_type, lock->ml.type, lock->ml.convert_type,
0472                lock->ml.node,
0473                dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)),
0474                dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)),
0475                !list_empty(&lock->ast_list),
0476                !list_empty(&lock->bast_list),
0477                lock->ast_pending, lock->bast_pending,
0478                lock->convert_pending, lock->lock_pending,
0479                lock->cancel_pending, lock->unlock_pending,
0480                kref_read(&lock->lock_refs));
0481     spin_unlock(&lock->spinlock);
0482 
0483     return out;
0484 }
0485 
0486 static int dump_lockres(struct dlm_lock_resource *res, char *buf, int len)
0487 {
0488     struct dlm_lock *lock;
0489     int i;
0490     int out = 0;
0491 
0492     out += scnprintf(buf + out, len - out, "NAME:");
0493     out += stringify_lockname(res->lockname.name, res->lockname.len,
0494                   buf + out, len - out);
0495     out += scnprintf(buf + out, len - out, "\n");
0496 
0497 #define DEBUG_LRES_VERSION  1
0498     out += scnprintf(buf + out, len - out,
0499             "LRES:%d,%d,%d,%ld,%d,%d,%d,%d,%d,%d,%d\n",
0500             DEBUG_LRES_VERSION,
0501             res->owner, res->state, res->last_used,
0502             !list_empty(&res->purge),
0503             !list_empty(&res->dirty),
0504             !list_empty(&res->recovering),
0505             res->inflight_locks, res->migration_pending,
0506             atomic_read(&res->asts_reserved),
0507             kref_read(&res->refs));
0508 
0509     /* refmap */
0510     out += scnprintf(buf + out, len - out, "RMAP:");
0511     out += stringify_nodemap(res->refmap, O2NM_MAX_NODES,
0512                  buf + out, len - out);
0513     out += scnprintf(buf + out, len - out, "\n");
0514 
0515     /* lvb */
0516     out += scnprintf(buf + out, len - out, "LVBX:");
0517     for (i = 0; i < DLM_LVB_LEN; i++)
0518         out += scnprintf(buf + out, len - out,
0519                     "%02x", (unsigned char)res->lvb[i]);
0520     out += scnprintf(buf + out, len - out, "\n");
0521 
0522     /* granted */
0523     list_for_each_entry(lock, &res->granted, list)
0524         out += dump_lock(lock, 0, buf + out, len - out);
0525 
0526     /* converting */
0527     list_for_each_entry(lock, &res->converting, list)
0528         out += dump_lock(lock, 1, buf + out, len - out);
0529 
0530     /* blocked */
0531     list_for_each_entry(lock, &res->blocked, list)
0532         out += dump_lock(lock, 2, buf + out, len - out);
0533 
0534     out += scnprintf(buf + out, len - out, "\n");
0535 
0536     return out;
0537 }
0538 
0539 static void *lockres_seq_start(struct seq_file *m, loff_t *pos)
0540 {
0541     struct debug_lockres *dl = m->private;
0542     struct dlm_ctxt *dlm = dl->dl_ctxt;
0543     struct dlm_lock_resource *oldres = dl->dl_res;
0544     struct dlm_lock_resource *res = NULL, *iter;
0545     struct list_head *track_list;
0546 
0547     spin_lock(&dlm->track_lock);
0548     if (oldres)
0549         track_list = &oldres->tracking;
0550     else {
0551         track_list = &dlm->tracking_list;
0552         if (list_empty(track_list)) {
0553             dl = NULL;
0554             spin_unlock(&dlm->track_lock);
0555             goto bail;
0556         }
0557     }
0558 
0559     list_for_each_entry(iter, track_list, tracking) {
0560         if (&iter->tracking != &dlm->tracking_list) {
0561             dlm_lockres_get(iter);
0562             res = iter;
0563         }
0564         break;
0565     }
0566     spin_unlock(&dlm->track_lock);
0567 
0568     if (oldres)
0569         dlm_lockres_put(oldres);
0570 
0571     dl->dl_res = res;
0572 
0573     if (res) {
0574         spin_lock(&res->spinlock);
0575         dump_lockres(res, dl->dl_buf, dl->dl_len - 1);
0576         spin_unlock(&res->spinlock);
0577     } else
0578         dl = NULL;
0579 
0580 bail:
0581     /* passed to seq_show */
0582     return dl;
0583 }
0584 
0585 static void lockres_seq_stop(struct seq_file *m, void *v)
0586 {
0587 }
0588 
0589 static void *lockres_seq_next(struct seq_file *m, void *v, loff_t *pos)
0590 {
0591     return NULL;
0592 }
0593 
0594 static int lockres_seq_show(struct seq_file *s, void *v)
0595 {
0596     struct debug_lockres *dl = (struct debug_lockres *)v;
0597 
0598     seq_printf(s, "%s", dl->dl_buf);
0599 
0600     return 0;
0601 }
0602 
0603 static const struct seq_operations debug_lockres_ops = {
0604     .start =    lockres_seq_start,
0605     .stop =     lockres_seq_stop,
0606     .next =     lockres_seq_next,
0607     .show =     lockres_seq_show,
0608 };
0609 
0610 static int debug_lockres_open(struct inode *inode, struct file *file)
0611 {
0612     struct dlm_ctxt *dlm = inode->i_private;
0613     struct debug_lockres *dl;
0614     void *buf;
0615 
0616     buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
0617     if (!buf)
0618         goto bail;
0619 
0620     dl = __seq_open_private(file, &debug_lockres_ops, sizeof(*dl));
0621     if (!dl)
0622         goto bailfree;
0623 
0624     dl->dl_len = PAGE_SIZE;
0625     dl->dl_buf = buf;
0626 
0627     dlm_grab(dlm);
0628     dl->dl_ctxt = dlm;
0629 
0630     return 0;
0631 
0632 bailfree:
0633     kfree(buf);
0634 bail:
0635     mlog_errno(-ENOMEM);
0636     return -ENOMEM;
0637 }
0638 
0639 static int debug_lockres_release(struct inode *inode, struct file *file)
0640 {
0641     struct seq_file *seq = file->private_data;
0642     struct debug_lockres *dl = (struct debug_lockres *)seq->private;
0643 
0644     if (dl->dl_res)
0645         dlm_lockres_put(dl->dl_res);
0646     dlm_put(dl->dl_ctxt);
0647     kfree(dl->dl_buf);
0648     return seq_release_private(inode, file);
0649 }
0650 
0651 static const struct file_operations debug_lockres_fops = {
0652     .open =     debug_lockres_open,
0653     .release =  debug_lockres_release,
0654     .read =     seq_read,
0655     .llseek =   seq_lseek,
0656 };
0657 /* end - debug lockres funcs */
0658 
0659 /* begin - debug state funcs */
0660 static int debug_state_print(struct dlm_ctxt *dlm, char *buf, int len)
0661 {
0662     int out = 0;
0663     struct dlm_reco_node_data *node;
0664     char *state;
0665     int cur_mles = 0, tot_mles = 0;
0666     int i;
0667 
0668     spin_lock(&dlm->spinlock);
0669 
0670     switch (dlm->dlm_state) {
0671     case DLM_CTXT_NEW:
0672         state = "NEW"; break;
0673     case DLM_CTXT_JOINED:
0674         state = "JOINED"; break;
0675     case DLM_CTXT_IN_SHUTDOWN:
0676         state = "SHUTDOWN"; break;
0677     case DLM_CTXT_LEAVING:
0678         state = "LEAVING"; break;
0679     default:
0680         state = "UNKNOWN"; break;
0681     }
0682 
0683     /* Domain: xxxxxxxxxx  Key: 0xdfbac769 */
0684     out += scnprintf(buf + out, len - out,
0685             "Domain: %s  Key: 0x%08x  Protocol: %d.%d\n",
0686             dlm->name, dlm->key, dlm->dlm_locking_proto.pv_major,
0687             dlm->dlm_locking_proto.pv_minor);
0688 
0689     /* Thread Pid: xxx  Node: xxx  State: xxxxx */
0690     out += scnprintf(buf + out, len - out,
0691             "Thread Pid: %d  Node: %d  State: %s\n",
0692             task_pid_nr(dlm->dlm_thread_task), dlm->node_num, state);
0693 
0694     /* Number of Joins: xxx  Joining Node: xxx */
0695     out += scnprintf(buf + out, len - out,
0696             "Number of Joins: %d  Joining Node: %d\n",
0697             dlm->num_joins, dlm->joining_node);
0698 
0699     /* Domain Map: xx xx xx */
0700     out += scnprintf(buf + out, len - out, "Domain Map: ");
0701     out += stringify_nodemap(dlm->domain_map, O2NM_MAX_NODES,
0702                  buf + out, len - out);
0703     out += scnprintf(buf + out, len - out, "\n");
0704 
0705     /* Exit Domain Map: xx xx xx */
0706     out += scnprintf(buf + out, len - out, "Exit Domain Map: ");
0707     out += stringify_nodemap(dlm->exit_domain_map, O2NM_MAX_NODES,
0708                  buf + out, len - out);
0709     out += scnprintf(buf + out, len - out, "\n");
0710 
0711     /* Live Map: xx xx xx */
0712     out += scnprintf(buf + out, len - out, "Live Map: ");
0713     out += stringify_nodemap(dlm->live_nodes_map, O2NM_MAX_NODES,
0714                  buf + out, len - out);
0715     out += scnprintf(buf + out, len - out, "\n");
0716 
0717     /* Lock Resources: xxx (xxx) */
0718     out += scnprintf(buf + out, len - out,
0719             "Lock Resources: %d (%d)\n",
0720             atomic_read(&dlm->res_cur_count),
0721             atomic_read(&dlm->res_tot_count));
0722 
0723     for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
0724         tot_mles += atomic_read(&dlm->mle_tot_count[i]);
0725 
0726     for (i = 0; i < DLM_MLE_NUM_TYPES; ++i)
0727         cur_mles += atomic_read(&dlm->mle_cur_count[i]);
0728 
0729     /* MLEs: xxx (xxx) */
0730     out += scnprintf(buf + out, len - out,
0731             "MLEs: %d (%d)\n", cur_mles, tot_mles);
0732 
0733     /*  Blocking: xxx (xxx) */
0734     out += scnprintf(buf + out, len - out,
0735             "  Blocking: %d (%d)\n",
0736             atomic_read(&dlm->mle_cur_count[DLM_MLE_BLOCK]),
0737             atomic_read(&dlm->mle_tot_count[DLM_MLE_BLOCK]));
0738 
0739     /*  Mastery: xxx (xxx) */
0740     out += scnprintf(buf + out, len - out,
0741             "  Mastery: %d (%d)\n",
0742             atomic_read(&dlm->mle_cur_count[DLM_MLE_MASTER]),
0743             atomic_read(&dlm->mle_tot_count[DLM_MLE_MASTER]));
0744 
0745     /*  Migration: xxx (xxx) */
0746     out += scnprintf(buf + out, len - out,
0747             "  Migration: %d (%d)\n",
0748             atomic_read(&dlm->mle_cur_count[DLM_MLE_MIGRATION]),
0749             atomic_read(&dlm->mle_tot_count[DLM_MLE_MIGRATION]));
0750 
0751     /* Lists: Dirty=Empty  Purge=InUse  PendingASTs=Empty  ... */
0752     out += scnprintf(buf + out, len - out,
0753             "Lists: Dirty=%s  Purge=%s  PendingASTs=%s  "
0754             "PendingBASTs=%s\n",
0755             (list_empty(&dlm->dirty_list) ? "Empty" : "InUse"),
0756             (list_empty(&dlm->purge_list) ? "Empty" : "InUse"),
0757             (list_empty(&dlm->pending_asts) ? "Empty" : "InUse"),
0758             (list_empty(&dlm->pending_basts) ? "Empty" : "InUse"));
0759 
0760     /* Purge Count: xxx  Refs: xxx */
0761     out += scnprintf(buf + out, len - out,
0762             "Purge Count: %d  Refs: %d\n", dlm->purge_count,
0763             kref_read(&dlm->dlm_refs));
0764 
0765     /* Dead Node: xxx */
0766     out += scnprintf(buf + out, len - out,
0767             "Dead Node: %d\n", dlm->reco.dead_node);
0768 
0769     /* What about DLM_RECO_STATE_FINALIZE? */
0770     if (dlm->reco.state == DLM_RECO_STATE_ACTIVE)
0771         state = "ACTIVE";
0772     else
0773         state = "INACTIVE";
0774 
0775     /* Recovery Pid: xxxx  Master: xxx  State: xxxx */
0776     out += scnprintf(buf + out, len - out,
0777             "Recovery Pid: %d  Master: %d  State: %s\n",
0778             task_pid_nr(dlm->dlm_reco_thread_task),
0779             dlm->reco.new_master, state);
0780 
0781     /* Recovery Map: xx xx */
0782     out += scnprintf(buf + out, len - out, "Recovery Map: ");
0783     out += stringify_nodemap(dlm->recovery_map, O2NM_MAX_NODES,
0784                  buf + out, len - out);
0785     out += scnprintf(buf + out, len - out, "\n");
0786 
0787     /* Recovery Node State: */
0788     out += scnprintf(buf + out, len - out, "Recovery Node State:\n");
0789     list_for_each_entry(node, &dlm->reco.node_data, list) {
0790         switch (node->state) {
0791         case DLM_RECO_NODE_DATA_INIT:
0792             state = "INIT";
0793             break;
0794         case DLM_RECO_NODE_DATA_REQUESTING:
0795             state = "REQUESTING";
0796             break;
0797         case DLM_RECO_NODE_DATA_DEAD:
0798             state = "DEAD";
0799             break;
0800         case DLM_RECO_NODE_DATA_RECEIVING:
0801             state = "RECEIVING";
0802             break;
0803         case DLM_RECO_NODE_DATA_REQUESTED:
0804             state = "REQUESTED";
0805             break;
0806         case DLM_RECO_NODE_DATA_DONE:
0807             state = "DONE";
0808             break;
0809         case DLM_RECO_NODE_DATA_FINALIZE_SENT:
0810             state = "FINALIZE-SENT";
0811             break;
0812         default:
0813             state = "BAD";
0814             break;
0815         }
0816         out += scnprintf(buf + out, len - out, "\t%u - %s\n",
0817                 node->node_num, state);
0818     }
0819 
0820     spin_unlock(&dlm->spinlock);
0821 
0822     return out;
0823 }
0824 
0825 static int debug_state_open(struct inode *inode, struct file *file)
0826 {
0827     struct dlm_ctxt *dlm = inode->i_private;
0828     char *buf = NULL;
0829 
0830     buf = (char *) get_zeroed_page(GFP_NOFS);
0831     if (!buf)
0832         goto bail;
0833 
0834     i_size_write(inode, debug_state_print(dlm, buf, PAGE_SIZE - 1));
0835 
0836     file->private_data = buf;
0837 
0838     return 0;
0839 bail:
0840     return -ENOMEM;
0841 }
0842 
0843 static const struct file_operations debug_state_fops = {
0844     .open =     debug_state_open,
0845     .release =  debug_release,
0846     .read =     debug_read,
0847     .llseek =   generic_file_llseek,
0848 };
0849 /* end  - debug state funcs */
0850 
0851 /* files in subroot */
0852 void dlm_debug_init(struct dlm_ctxt *dlm)
0853 {
0854     /* for dumping dlm_ctxt */
0855     debugfs_create_file(DLM_DEBUGFS_DLM_STATE, S_IFREG|S_IRUSR,
0856                 dlm->dlm_debugfs_subroot, dlm, &debug_state_fops);
0857 
0858     /* for dumping lockres */
0859     debugfs_create_file(DLM_DEBUGFS_LOCKING_STATE, S_IFREG|S_IRUSR,
0860                 dlm->dlm_debugfs_subroot, dlm, &debug_lockres_fops);
0861 
0862     /* for dumping mles */
0863     debugfs_create_file(DLM_DEBUGFS_MLE_STATE, S_IFREG|S_IRUSR,
0864                 dlm->dlm_debugfs_subroot, dlm, &debug_mle_fops);
0865 
0866     /* for dumping lockres on the purge list */
0867     debugfs_create_file(DLM_DEBUGFS_PURGE_LIST, S_IFREG|S_IRUSR,
0868                 dlm->dlm_debugfs_subroot, dlm,
0869                 &debug_purgelist_fops);
0870 }
0871 
0872 /* subroot - domain dir */
0873 void dlm_create_debugfs_subroot(struct dlm_ctxt *dlm)
0874 {
0875     dlm->dlm_debugfs_subroot = debugfs_create_dir(dlm->name,
0876                               dlm_debugfs_root);
0877 }
0878 
0879 void dlm_destroy_debugfs_subroot(struct dlm_ctxt *dlm)
0880 {
0881     debugfs_remove_recursive(dlm->dlm_debugfs_subroot);
0882 }
0883 
0884 /* debugfs root */
0885 void dlm_create_debugfs_root(void)
0886 {
0887     dlm_debugfs_root = debugfs_create_dir(DLM_DEBUGFS_DIR, NULL);
0888 }
0889 
0890 void dlm_destroy_debugfs_root(void)
0891 {
0892     debugfs_remove(dlm_debugfs_root);
0893 }
0894 #endif  /* CONFIG_DEBUG_FS */