0001
0002
0003
0004
0005
0006
0007
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
0229
0230
0231
0232
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
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
0346
0347
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
0402
0403
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
0460
0461
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
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
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
0523 list_for_each_entry(lock, &res->granted, list)
0524 out += dump_lock(lock, 0, buf + out, len - out);
0525
0526
0527 list_for_each_entry(lock, &res->converting, list)
0528 out += dump_lock(lock, 1, buf + out, len - out);
0529
0530
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
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
0658
0659
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
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
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
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
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
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
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
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
0730 out += scnprintf(buf + out, len - out,
0731 "MLEs: %d (%d)\n", cur_mles, tot_mles);
0732
0733
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
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
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
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
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
0766 out += scnprintf(buf + out, len - out,
0767 "Dead Node: %d\n", dlm->reco.dead_node);
0768
0769
0770 if (dlm->reco.state == DLM_RECO_STATE_ACTIVE)
0771 state = "ACTIVE";
0772 else
0773 state = "INACTIVE";
0774
0775
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
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
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
0850
0851
0852 void dlm_debug_init(struct dlm_ctxt *dlm)
0853 {
0854
0855 debugfs_create_file(DLM_DEBUGFS_DLM_STATE, S_IFREG|S_IRUSR,
0856 dlm->dlm_debugfs_subroot, dlm, &debug_state_fops);
0857
0858
0859 debugfs_create_file(DLM_DEBUGFS_LOCKING_STATE, S_IFREG|S_IRUSR,
0860 dlm->dlm_debugfs_subroot, dlm, &debug_lockres_fops);
0861
0862
0863 debugfs_create_file(DLM_DEBUGFS_MLE_STATE, S_IFREG|S_IRUSR,
0864 dlm->dlm_debugfs_subroot, dlm, &debug_mle_fops);
0865
0866
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
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
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