Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3153484
proc.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
15 KB
Referenced Files
None
Subscribers
None
proc.c
View Options
/******************************************************************************
*******************************************************************************
**
** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
** Copyright (C) 2004 Red Hat, Inc. All rights reserved.
**
** This copyrighted material is made available to anyone wishing to use,
** modify, copy, or redistribute it subject to the terms and conditions
** of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/module.h>
#include "dlm_internal.h"
#include "lockspace.h"
#if defined(DLM_DEBUG)
#define DLM_DEBUG_SIZE (1024)
#define MAX_DEBUG_MSG_LEN (64)
#else
#define DLM_DEBUG_SIZE (0)
#define MAX_DEBUG_MSG_LEN (0)
#endif
static char * debug_buf;
static unsigned int debug_size;
static unsigned int debug_point;
static int debug_wrap;
static spinlock_t debug_lock;
static struct proc_dir_entry * debug_proc_entry = NULL;
static char proc_ls_name[255] = "";
#ifdef CONFIG_CLUSTER_DLM_PROCLOCKS
static struct proc_dir_entry * locks_proc_entry = NULL;
static struct seq_operations locks_info_op;
static struct proc_dir_entry * dir_proc_entry = NULL;
static struct seq_operations dir_info_op;
/*
* /proc/cluster/dlm_locks - dump resources and locks
*/
static int locks_open(struct inode *inode, struct file *file)
{
return seq_open(file, &locks_info_op);
}
/* Write simply sets the lockspace to use */
static ssize_t locks_write(struct file *file, const char *buf,
size_t count, loff_t * ppos)
{
int error;
if (count < sizeof(proc_ls_name)) {
error = copy_from_user(proc_ls_name, buf, count);
if (error)
return error;
proc_ls_name[count] = '\0';
/* Remove any trailing LF so that lazy users
can just echo "lsname" > /proc/cluster/dlm_locks */
if (proc_ls_name[count - 1] == '\n')
proc_ls_name[count - 1] = '\0';
return count;
}
return 0;
}
static struct file_operations locks_fops = {
open:locks_open,
write:locks_write,
read:seq_read,
llseek:seq_lseek,
release:seq_release,
};
struct ls_dumpinfo {
int entry;
struct list_head *next;
struct dlm_ls *ls;
struct dlm_rsb *rsb;
struct dlm_direntry *de;
};
static int print_resource(struct dlm_rsb * res, struct seq_file *s);
static struct ls_dumpinfo *next_rsb(struct ls_dumpinfo *di)
{
int i;
if (!di->next) {
/* Find the next non-empty hash bucket */
for (i = di->entry; i < di->ls->ls_rsbtbl_size; i++) {
read_lock(&di->ls->ls_rsbtbl[i].lock);
if (!list_empty(&di->ls->ls_rsbtbl[i].list)) {
di->next = di->ls->ls_rsbtbl[i].list.next;
read_unlock(&di->ls->ls_rsbtbl[i].lock);
break;
}
read_unlock(&di->ls->ls_rsbtbl[i].lock);
}
di->entry = i;
if (di->entry >= di->ls->ls_rsbtbl_size)
return NULL; /* End of hash list */
} else { /* Find the next entry in the list */
i = di->entry;
read_lock(&di->ls->ls_rsbtbl[i].lock);
di->next = di->next->next;
if (di->next->next == di->ls->ls_rsbtbl[i].list.next) {
/* End of list - move to next bucket */
di->next = NULL;
di->entry++;
read_unlock(&di->ls->ls_rsbtbl[i].lock);
return next_rsb(di); /* do the top half of this conditional */
}
read_unlock(&di->ls->ls_rsbtbl[i].lock);
}
di->rsb = list_entry(di->next, struct dlm_rsb, res_hashchain);
return di;
}
static void *s_start(struct seq_file *m, loff_t *pos)
{
struct ls_dumpinfo *di;
struct dlm_ls *ls;
int i;
ls = find_lockspace_by_name(proc_ls_name, strlen(proc_ls_name));
if (!ls)
return NULL;
if (!m->private) {
di = kmalloc(sizeof(struct ls_dumpinfo), GFP_KERNEL);
m->private = di;
if (!di)
return NULL;
}
else
di = m->private;
if (*pos == 0)
seq_printf(m, "DLM lockspace '%s'\n", proc_ls_name);
di->entry = 0;
di->next = NULL;
di->ls = ls;
di->de = NULL;
for (i = 0; i < *pos; i++)
if (next_rsb(di) == NULL)
return NULL;
return next_rsb(di);
}
static void *s_next(struct seq_file *m, void *p, loff_t *pos)
{
struct ls_dumpinfo *di = p;
*pos += 1;
return next_rsb(di);
}
static int s_show(struct seq_file *m, void *p)
{
struct ls_dumpinfo *di = p;
return print_resource(di->rsb, m);
}
static void s_stop(struct seq_file *m, void *p)
{
if (m->private) {
kfree(m->private);
m->private = NULL;
}
}
static struct seq_operations locks_info_op = {
start:s_start,
next:s_next,
stop:s_stop,
show:s_show
};
static char *print_lockmode(int mode)
{
switch (mode) {
case DLM_LOCK_IV:
return "--";
case DLM_LOCK_NL:
return "NL";
case DLM_LOCK_CR:
return "CR";
case DLM_LOCK_CW:
return "CW";
case DLM_LOCK_PR:
return "PR";
case DLM_LOCK_PW:
return "PW";
case DLM_LOCK_EX:
return "EX";
default:
return "??";
}
}
static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
struct dlm_rsb *res)
{
seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
if (lkb->lkb_status == GDLM_LKSTS_CONVERT
|| lkb->lkb_status == GDLM_LKSTS_WAITING)
seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
if (lkb->lkb_range) {
/* This warns on Alpha. Tough. Only I see it */
if (lkb->lkb_status == GDLM_LKSTS_CONVERT
|| lkb->lkb_status == GDLM_LKSTS_GRANTED)
seq_printf(s, " %" PRIx64 "-%" PRIx64,
lkb->lkb_range[GR_RANGE_START],
lkb->lkb_range[GR_RANGE_END]);
if (lkb->lkb_status == GDLM_LKSTS_CONVERT
|| lkb->lkb_status == GDLM_LKSTS_WAITING)
seq_printf(s, " (%" PRIx64 "-%" PRIx64 ")",
lkb->lkb_range[RQ_RANGE_START],
lkb->lkb_range[RQ_RANGE_END]);
}
if (lkb->lkb_nodeid) {
if (lkb->lkb_nodeid != res->res_nodeid)
seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
lkb->lkb_remid);
else
seq_printf(s, " Master: %08x", lkb->lkb_remid);
}
if (lkb->lkb_status != GDLM_LKSTS_GRANTED)
seq_printf(s, " LQ: %d,0x%x", lkb->lkb_lockqueue_state,
lkb->lkb_lockqueue_flags);
seq_printf(s, "\n");
}
static int print_resource(struct dlm_rsb *res, struct seq_file *s)
{
int i;
struct list_head *locklist;
seq_printf(s, "\nResource %p (parent %p). Name (len=%d) \"", res,
res->res_parent, res->res_length);
for (i = 0; i < res->res_length; i++) {
if (isprint(res->res_name[i]))
seq_printf(s, "%c", res->res_name[i]);
else
seq_printf(s, "%c", '.');
}
if (res->res_nodeid)
seq_printf(s, "\" \nLocal Copy, Master is node %d\n",
res->res_nodeid);
else
seq_printf(s, "\" \nMaster Copy\n");
/* Print the LVB: */
if (res->res_lvbptr) {
seq_printf(s, "LVB: ");
for (i = 0; i < DLM_LVB_LEN; i++) {
if (i == DLM_LVB_LEN / 2)
seq_printf(s, "\n ");
seq_printf(s, "%02x ",
(unsigned char) res->res_lvbptr[i]);
}
if (test_bit(RESFL_VALNOTVALID, &res->res_flags))
seq_printf(s, " (INVALID)");
seq_printf(s, "\n");
}
/* Print the locks attached to this resource */
seq_printf(s, "Granted Queue\n");
list_for_each(locklist, &res->res_grantqueue) {
struct dlm_lkb *this_lkb =
list_entry(locklist, struct dlm_lkb, lkb_statequeue);
print_lock(s, this_lkb, res);
}
seq_printf(s, "Conversion Queue\n");
list_for_each(locklist, &res->res_convertqueue) {
struct dlm_lkb *this_lkb =
list_entry(locklist, struct dlm_lkb, lkb_statequeue);
print_lock(s, this_lkb, res);
}
seq_printf(s, "Waiting Queue\n");
list_for_each(locklist, &res->res_waitqueue) {
struct dlm_lkb *this_lkb =
list_entry(locklist, struct dlm_lkb, lkb_statequeue);
print_lock(s, this_lkb, res);
}
return 0;
}
/*
* /proc/cluster/dlm_dir - dump resource directory
*/
static int print_de(struct dlm_direntry *de, struct seq_file *s)
{
char strname[DLM_RESNAME_MAXLEN+1];
memset(strname, 0, DLM_RESNAME_MAXLEN+1);
memcpy(strname, de->name, de->length);
seq_printf(s, "%s %u\n", strname, de->master_nodeid);
return 0;
}
static int dir_open(struct inode *inode, struct file *file)
{
return seq_open(file, &dir_info_op);
}
static ssize_t dir_write(struct file *file, const char *buf,
size_t count, loff_t *ppos)
{
return locks_write(file, buf, count, ppos);
}
static struct file_operations dir_fops = {
.open = dir_open,
.write = dir_write,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.owner = THIS_MODULE,
};
static struct ls_dumpinfo *next_de(struct ls_dumpinfo *di)
{
int i;
if (!di->next) {
/* Find the next non-empty hash bucket */
for (i = di->entry; i < di->ls->ls_dirtbl_size; i++) {
read_lock(&di->ls->ls_dirtbl[i].lock);
if (!list_empty(&di->ls->ls_dirtbl[i].list)) {
di->next = di->ls->ls_dirtbl[i].list.next;
read_unlock(&di->ls->ls_dirtbl[i].lock);
break;
}
read_unlock(&di->ls->ls_dirtbl[i].lock);
}
di->entry = i;
if (di->entry >= di->ls->ls_dirtbl_size)
return NULL; /* End of hash list */
} else { /* Find the next entry in the list */
i = di->entry;
read_lock(&di->ls->ls_dirtbl[i].lock);
di->next = di->next->next;
if (di->next->next == di->ls->ls_dirtbl[i].list.next) {
/* End of list - move to next bucket */
di->next = NULL;
di->entry++;
read_unlock(&di->ls->ls_dirtbl[i].lock);
return next_de(di); /* do the top half of this conditional */
}
read_unlock(&di->ls->ls_dirtbl[i].lock);
}
di->de = list_entry(di->next, struct dlm_direntry, list);
return di;
}
static void *dir_start(struct seq_file *m, loff_t *pos)
{
struct ls_dumpinfo *di;
struct dlm_ls *ls;
int i;
ls = find_lockspace_by_name(proc_ls_name, strlen(proc_ls_name));
if (!ls)
return NULL;
if (!m->private) {
di = kmalloc(sizeof(struct ls_dumpinfo), GFP_KERNEL);
m->private = di;
if (!di)
return NULL;
}
else
di = m->private;
if (*pos == 0)
seq_printf(m, "DLM lockspace '%s'\n", proc_ls_name);
di->entry = 0;
di->next = NULL;
di->ls = ls;
for (i = 0; i < *pos; i++)
if (next_de(di) == NULL)
return NULL;
return next_de(di);
}
static void *dir_next(struct seq_file *m, void *p, loff_t *pos)
{
struct ls_dumpinfo *di = p;
*pos += 1;
return next_de(di);
}
static int dir_show(struct seq_file *m, void *p)
{
struct ls_dumpinfo *di = p;
return print_de(di->de, m);
}
static void dir_stop(struct seq_file *m, void *p)
{
if (m->private) {
kfree(m->private);
m->private = NULL;
}
}
static struct seq_operations dir_info_op = {
.start = dir_start,
.next = dir_next,
.stop = dir_stop,
.show = dir_show,
};
#endif /* CONFIG_CLUSTER_DLM_PROCLOCKS */
void dlm_debug_log(struct dlm_ls *ls, const char *fmt, ...)
{
va_list va;
int i, n, size, len;
char buf[MAX_DEBUG_MSG_LEN+1];
spin_lock(&debug_lock);
if (!debug_buf)
goto out;
size = MAX_DEBUG_MSG_LEN;
memset(buf, 0, size+1);
n = snprintf(buf, size, "%s ", ls->ls_name);
size -= n;
va_start(va, fmt);
vsnprintf(buf+n, size, fmt, va);
va_end(va);
len = strlen(buf);
if (len > MAX_DEBUG_MSG_LEN-1)
len = MAX_DEBUG_MSG_LEN-1;
buf[len] = '\n';
buf[len+1] = '\0';
for (i = 0; i < strlen(buf); i++) {
debug_buf[debug_point++] = buf[i];
if (debug_point == debug_size) {
debug_point = 0;
debug_wrap = 1;
}
}
out:
spin_unlock(&debug_lock);
}
void dlm_debug_dump(void)
{
int i;
spin_lock(&debug_lock);
if (debug_wrap) {
for (i = debug_point; i < debug_size; i++)
printk("%c", debug_buf[i]);
}
for (i = 0; i < debug_point; i++)
printk("%c", debug_buf[i]);
spin_unlock(&debug_lock);
}
void dlm_debug_setup(int size)
{
char *b = NULL;
if (size > PAGE_SIZE)
size = PAGE_SIZE;
if (size)
b = kmalloc(size, GFP_KERNEL);
spin_lock(&debug_lock);
if (debug_buf)
kfree(debug_buf);
if (!size || !b)
goto out;
debug_size = size;
debug_point = 0;
debug_wrap = 0;
debug_buf = b;
memset(debug_buf, 0, debug_size);
out:
spin_unlock(&debug_lock);
}
static void dlm_debug_init(void)
{
debug_buf = NULL;
debug_size = 0;
debug_point = 0;
debug_wrap = 0;
spin_lock_init(&debug_lock);
dlm_debug_setup(DLM_DEBUG_SIZE);
}
#ifdef CONFIG_PROC_FS
int dlm_debug_info(char *b, char **start, off_t offset, int length)
{
int i, n = 0;
spin_lock(&debug_lock);
if (debug_wrap) {
for (i = debug_point; i < debug_size; i++)
n += sprintf(b + n, "%c", debug_buf[i]);
}
for (i = 0; i < debug_point; i++)
n += sprintf(b + n, "%c", debug_buf[i]);
spin_unlock(&debug_lock);
return n;
}
#endif
#ifdef CONFIG_DLM_STATS
struct dlm_statinfo dlm_stats;
static struct proc_dir_entry *stats_proc_entry = NULL;
static int dlm_stats_info(char *b, char **start, off_t offset, int length)
{
int n=0;
int i;
long lq_locks = 0;
unsigned long lq_time = 0;
n += sprintf(b+n, "DLM stats (HZ=%d)\n\n", HZ);
n += sprintf(b+n, "Lock operations: %7d\n", dlm_stats.lockops);
n += sprintf(b+n, "Unlock operations: %7d\n", dlm_stats.unlockops);
n += sprintf(b+n, "Convert operations: %7d\n", dlm_stats.convertops);
n += sprintf(b+n, "Completion ASTs: %7d\n", dlm_stats.cast);
n += sprintf(b+n, "Blocking ASTs: %7d\n", dlm_stats.bast);
n += sprintf(b+n, "\n");
n += sprintf(b+n, "Lockqueue num waittime ave\n");
for (i=1; i<=4 ; i++) {
char *lq_reason="???";
switch (i){
case 1: lq_reason = "WAIT_RSB ";
break;
case 2: lq_reason = "WAIT_CONV ";
break;
case 3: lq_reason = "WAIT_GRANT ";
break;
case 4: lq_reason = "WAIT_UNLOCK";
break;
}
if (dlm_stats.lockqueue_locks[i])
n += sprintf(b+n, "%s %6lu %7lu %3lu\n",
lq_reason,
dlm_stats.lockqueue_locks[i],
dlm_stats.lockqueue_time[i],
dlm_stats.lockqueue_time[i]/
dlm_stats.lockqueue_locks[i]);
lq_locks += dlm_stats.lockqueue_locks[i];
lq_time += dlm_stats.lockqueue_time[i];
}
if (lq_locks)
n += sprintf(b+n, "Total %6lu %7lu %3lu\n",
lq_locks, lq_time, lq_time/lq_locks);
return n;
}
static int dlm_stats_clear(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{
memset(&dlm_stats, 0, sizeof(dlm_stats));
return count;
}
#endif /* CONFIG_DLM_STATS */
void dlm_proc_init(void)
{
#ifdef CONFIG_PROC_FS
debug_proc_entry = create_proc_entry("cluster/dlm_debug", S_IRUGO,
NULL);
if (!debug_proc_entry)
return;
debug_proc_entry->get_info = &dlm_debug_info;
#endif
#ifdef CONFIG_DLM_STATS
stats_proc_entry = create_proc_entry("cluster/dlm_stats",
S_IRUSR | S_IWUSR, NULL);
if (!stats_proc_entry)
return;
stats_proc_entry->get_info = &dlm_stats_info;
stats_proc_entry->write_proc = &dlm_stats_clear;
#endif
dlm_debug_init();
#ifdef CONFIG_CLUSTER_DLM_PROCLOCKS
locks_proc_entry = create_proc_read_entry("cluster/dlm_locks",
S_IFREG | 0400,
NULL, NULL, NULL);
if (!locks_proc_entry)
return;
locks_proc_entry->proc_fops = &locks_fops;
dir_proc_entry = create_proc_read_entry("cluster/dlm_dir",
S_IFREG | 0400,
NULL, NULL, NULL);
if (!dir_proc_entry)
return;
dir_proc_entry->proc_fops = &dir_fops;
#endif
}
void dlm_proc_exit(void)
{
#ifdef CONFIG_PROC_FS
if (debug_proc_entry) {
remove_proc_entry("cluster/dlm_debug", NULL);
dlm_debug_setup(0);
}
#endif
#ifdef CONFIG_DLM_STATS
if (stats_proc_entry)
remove_proc_entry("cluster/dlm_stats", NULL);
#endif
#ifdef CONFIG_CLUSTER_DLM_PROCLOCKS
if (locks_proc_entry)
remove_proc_entry("cluster/dlm_locks", NULL);
if (dir_proc_entry)
remove_proc_entry("cluster/dlm_dir", NULL);
#endif
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Tue, Feb 25, 7:54 PM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464959
Default Alt Text
proc.c (15 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment