📄 dlmdebug.c
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dlmdebug.c * * debug functionality for the dlm * * Copyright (C) 2004 Oracle. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. * */#include <linux/types.h>#include <linux/slab.h>#include <linux/highmem.h>#include <linux/utsname.h>#include <linux/sysctl.h>#include <linux/spinlock.h>#include <linux/proc_fs.h>#include "cluster/heartbeat.h"#include "cluster/nodemanager.h"#include "cluster/tcp.h"#include "dlmapi.h"#include "dlmcommon.h"#include "dlmdebug.h"#include "dlmdomain.h"#include "dlmdebug.h"#define MLOG_MASK_PREFIX ML_DLM#include "cluster/masklog.h"static int dlm_dump_all_lock_resources(const char __user *data, unsigned int len);static void dlm_dump_purge_list(struct dlm_ctxt *dlm);static int dlm_dump_all_purge_lists(const char __user *data, unsigned int len);static int dlm_trigger_migration(const char __user *data, unsigned int len);static int dlm_dump_one_lock_resource(const char __user *data, unsigned int len);static int dlm_dump_work_queues(const char __user *data, unsigned int len);static int dlm_parse_domain_and_lockres(char *buf, unsigned int len, struct dlm_ctxt **dlm, struct dlm_lock_resource **res);static int dlm_proc_stats(char *page, char **start, off_t off, int count, int *eof, void *data);typedef int (dlm_debug_func_t)(const char __user *data, unsigned int len);struct dlm_debug_funcs{ char key; dlm_debug_func_t *func;};static struct dlm_debug_funcs dlm_debug_map[] = { { 'r', dlm_dump_all_lock_resources }, { 'R', dlm_dump_one_lock_resource }, { 'm', dlm_dump_all_mles }, { 'p', dlm_dump_all_purge_lists }, { 'M', dlm_trigger_migration }, { 'w', dlm_dump_work_queues }};static int dlm_debug_map_sz = (sizeof(dlm_debug_map) / sizeof(struct dlm_debug_funcs));static ssize_t write_dlm_debug(struct file *file, const char __user *buf, size_t count, loff_t *ppos){ int i; char c; dlm_debug_func_t *fn; int ret; mlog(0, "(%p, %p, %u, %lld)\n", file, buf, (unsigned int)count, (long long)*ppos); ret = 0; if (count<=0) goto done; ret = -EFAULT; if (get_user(c, buf)) goto done; ret = count; for (i=0; i < dlm_debug_map_sz; i++) { struct dlm_debug_funcs *d = &dlm_debug_map[i]; if (c == d->key) { fn = d->func; if (fn) ret = (fn)(buf, count); goto done; } }done: return ret;}static struct file_operations dlm_debug_operations = { .write = write_dlm_debug,};#define OCFS2_DLM_PROC_PATH "fs/ocfs2_dlm"#define DLM_DEBUG_PROC_NAME "debug"#define DLM_STAT_PROC_NAME "stat"static struct proc_dir_entry *ocfs2_dlm_proc;void dlm_remove_proc(void){ if (ocfs2_dlm_proc) { remove_proc_entry(DLM_DEBUG_PROC_NAME, ocfs2_dlm_proc); remove_proc_entry(OCFS2_DLM_PROC_PATH, NULL); }}void dlm_init_proc(void){ struct proc_dir_entry *entry; ocfs2_dlm_proc = proc_mkdir(OCFS2_DLM_PROC_PATH, NULL); if (!ocfs2_dlm_proc) { mlog_errno(-ENOMEM); return; } entry = create_proc_entry(DLM_DEBUG_PROC_NAME, S_IWUSR, ocfs2_dlm_proc); if (entry) entry->proc_fops = &dlm_debug_operations;}static int dlm_proc_stats(char *page, char **start, off_t off, int count, int *eof, void *data){ int len; struct dlm_ctxt *dlm = data; len = sprintf(page, "local=%d, remote=%d, unknown=%d, key=0x%08x\n", atomic_read(&dlm->local_resources), atomic_read(&dlm->remote_resources), atomic_read(&dlm->unknown_resources), dlm->key); if (len <= off + count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len;}void dlm_proc_add_domain(struct dlm_ctxt *dlm){ struct proc_dir_entry *entry; dlm->dlm_proc = proc_mkdir(dlm->name, ocfs2_dlm_proc); if (dlm->dlm_proc) { entry = create_proc_read_entry(DLM_STAT_PROC_NAME, S_IFREG | S_IRUGO, dlm->dlm_proc, dlm_proc_stats, (char *)dlm); if (entry) entry->owner = THIS_MODULE; }}void dlm_proc_del_domain(struct dlm_ctxt *dlm){ if (dlm->dlm_proc) { remove_proc_entry(DLM_STAT_PROC_NAME, dlm->dlm_proc); remove_proc_entry(dlm->name, ocfs2_dlm_proc); }}/* lock resource printing is usually very important (printed * right before a BUG in some cases), but we'd like to be * able to shut it off if needed, hence the KERN_NOTICE level */static int dlm_dump_all_lock_resources(const char __user *data, unsigned int len){ struct dlm_ctxt *dlm; struct list_head *iter; mlog(ML_NOTICE, "dumping ALL dlm state for node %s\n", system_utsname.nodename); spin_lock(&dlm_domain_lock); list_for_each(iter, &dlm_domains) { dlm = list_entry (iter, struct dlm_ctxt, list); dlm_dump_lock_resources(dlm); } spin_unlock(&dlm_domain_lock); return len;}static int dlm_dump_one_lock_resource(const char __user *data, unsigned int len){ struct dlm_ctxt *dlm; struct dlm_lock_resource *res; char *buf = NULL; int ret = -EINVAL; int tmpret; if (len >= PAGE_SIZE-1) { mlog(ML_ERROR, "user passed too much data: %d bytes\n", len); goto leave; } if (len < 5) { mlog(ML_ERROR, "user passed too little data: %d bytes\n", len); goto leave; } buf = kmalloc(len+1, GFP_NOFS); if (!buf) { mlog(ML_ERROR, "could not alloc %d bytes\n", len+1); ret = -ENOMEM; goto leave; } if (strncpy_from_user(buf, data, len) < len) { mlog(ML_ERROR, "failed to get all user data. done.\n"); goto leave; } buf[len]='\0'; mlog(0, "got this data from user: %s\n", buf); if (*buf != 'R') { mlog(0, "bad data\n"); goto leave; } tmpret = dlm_parse_domain_and_lockres(buf, len, &dlm, &res); if (tmpret < 0) { mlog(0, "bad data\n"); goto leave; } mlog(ML_NOTICE, "struct dlm_ctxt: %s, node=%u, key=%u\n", dlm->name, dlm->node_num, dlm->key); dlm_print_one_lock_resource(res); dlm_lockres_put(res); dlm_put(dlm); ret = len;leave: if (buf) kfree(buf); return ret;}static void dlm_print_lockres_refmap(struct dlm_lock_resource *res){ int bit; assert_spin_locked(&res->spinlock); mlog(ML_NOTICE, " refmap nodes: [ "); bit = 0; while (1) { bit = find_next_bit(res->refmap, O2NM_MAX_NODES, bit); if (bit >= O2NM_MAX_NODES) break; printk("%u ", bit); bit++; } printk("], inflight=%u\n", res->inflight_locks);}void dlm_print_one_lock_resource(struct dlm_lock_resource *res){ mlog(ML_NOTICE, "lockres: %.*s, owner=%u, state=%u\n", res->lockname.len, res->lockname.name, res->owner, res->state); spin_lock(&res->spinlock); __dlm_print_one_lock_resource(res); spin_unlock(&res->spinlock);}void __dlm_print_one_lock_resource(struct dlm_lock_resource *res){ struct list_head *iter2; struct dlm_lock *lock; assert_spin_locked(&res->spinlock); mlog(ML_NOTICE, "lockres: %.*s, owner=%u, state=%u\n", res->lockname.len, res->lockname.name, res->owner, res->state); mlog(ML_NOTICE, " last used: %lu, on purge list: %s\n", res->last_used, list_empty(&res->purge) ? "no" : "yes"); dlm_print_lockres_refmap(res); mlog(ML_NOTICE, " granted queue: \n"); list_for_each(iter2, &res->granted) { lock = list_entry(iter2, struct dlm_lock, list); spin_lock(&lock->spinlock); mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, " "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", lock->ml.type, lock->ml.convert_type, lock->ml.node, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), list_empty(&lock->ast_list) ? 'y' : 'n', lock->ast_pending ? 'y' : 'n', list_empty(&lock->bast_list) ? 'y' : 'n', lock->bast_pending ? 'y' : 'n'); spin_unlock(&lock->spinlock); } mlog(ML_NOTICE, " converting queue: \n"); list_for_each(iter2, &res->converting) { lock = list_entry(iter2, struct dlm_lock, list); spin_lock(&lock->spinlock); mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, " "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", lock->ml.type, lock->ml.convert_type, lock->ml.node, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), list_empty(&lock->ast_list) ? 'y' : 'n', lock->ast_pending ? 'y' : 'n', list_empty(&lock->bast_list) ? 'y' : 'n', lock->bast_pending ? 'y' : 'n'); spin_unlock(&lock->spinlock); } mlog(ML_NOTICE, " blocked queue: \n"); list_for_each(iter2, &res->blocked) { lock = list_entry(iter2, struct dlm_lock, list); spin_lock(&lock->spinlock); mlog(ML_NOTICE, " type=%d, conv=%d, node=%u, " "cookie=%u:%llu, ast=(empty=%c,pend=%c), bast=(empty=%c,pend=%c)\n", lock->ml.type, lock->ml.convert_type, lock->ml.node, dlm_get_lock_cookie_node(be64_to_cpu(lock->ml.cookie)), dlm_get_lock_cookie_seq(be64_to_cpu(lock->ml.cookie)), list_empty(&lock->ast_list) ? 'y' : 'n',
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -