From b4d6c3d1bb461d2c8a396c9ed3881a4da40fc6ab Mon Sep 17 00:00:00 2001 From: Vijay Bellur Date: Sat, 15 Aug 2009 12:58:08 +0000 Subject: TAKE2[PATCH BUG:213 1/1] Support for Process State Dump Support for process state dump. Signed-off-by: Anand V. Avati BUG: 213 (Support for process state dump) URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=213 --- libglusterfs/src/Makefile.am | 4 +- libglusterfs/src/fd.c | 67 ++++++++++++++ libglusterfs/src/inode.c | 76 +++++++++++++++ libglusterfs/src/iobuf.c | 104 +++++++++++++++++++++ libglusterfs/src/iobuf.h | 1 + libglusterfs/src/stack.c | 171 ++++++++++++++++++++++++++++++++++ libglusterfs/src/stack.h | 6 +- libglusterfs/src/statedump.c | 213 +++++++++++++++++++++++++++++++++++++++++++ libglusterfs/src/statedump.h | 78 ++++++++++++++++ libglusterfs/src/xlator.c | 5 + libglusterfs/src/xlator.h | 22 ++++- 11 files changed, 740 insertions(+), 7 deletions(-) create mode 100644 libglusterfs/src/stack.c create mode 100644 libglusterfs/src/statedump.c create mode 100644 libglusterfs/src/statedump.h (limited to 'libglusterfs') diff --git a/libglusterfs/src/Makefile.am b/libglusterfs/src/Makefile.am index 7698661fa..a3fb923ca 100644 --- a/libglusterfs/src/Makefile.am +++ b/libglusterfs/src/Makefile.am @@ -6,9 +6,9 @@ libglusterfs_la_LIBADD = @LEXLIB@ lib_LTLIBRARIES = libglusterfs.la -libglusterfs_la_SOURCES = dict.c spec.lex.c y.tab.c xlator.c logging.c hashfn.c defaults.c scheduler.c common-utils.c transport.c timer.c inode.c call-stub.c compat.c authenticate.c fd.c compat-errno.c event.c mem-pool.c gf-dirent.c syscall.c iobuf.c globals.c +libglusterfs_la_SOURCES = dict.c spec.lex.c y.tab.c xlator.c logging.c hashfn.c defaults.c scheduler.c common-utils.c transport.c timer.c inode.c call-stub.c compat.c authenticate.c fd.c compat-errno.c event.c mem-pool.c gf-dirent.c syscall.c iobuf.c globals.c statedump.c stack.c -noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h logging.h protocol.h scheduler.h xlator.h transport.h stack.h timer.h list.h inode.h call-stub.h compat.h authenticate.h fd.h revision.h compat-errno.h event.h mem-pool.h byte-order.h gf-dirent.h locking.h syscall.h iobuf.h globals.h +noinst_HEADERS = common-utils.h defaults.h dict.h glusterfs.h hashfn.h logging.h protocol.h scheduler.h xlator.h transport.h stack.h timer.h list.h inode.h call-stub.h compat.h authenticate.h fd.h revision.h compat-errno.h event.h mem-pool.h byte-order.h gf-dirent.h locking.h syscall.h iobuf.h globals.h statedump.h EXTRA_DIST = spec.l spec.y diff --git a/libglusterfs/src/fd.c b/libglusterfs/src/fd.c index 8f7616929..62536fc55 100644 --- a/libglusterfs/src/fd.c +++ b/libglusterfs/src/fd.c @@ -21,6 +21,7 @@ #include "glusterfs.h" #include "inode.h" #include "dict.h" +#include "statedump.h" #ifndef _CONFIG_H @@ -685,3 +686,69 @@ fd_ctx_del (fd_t *fd, xlator_t *xlator, uint64_t *value) return ret; } + + +void +fd_dump (fd_t *fd, char *prefix) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + inode_t *inode = NULL; + + if (!fd) + return; + + memset(key, 0, sizeof(key)); + gf_proc_dump_build_key(key, prefix, "pid"); + gf_proc_dump_write(key, "%d", fd->pid); + gf_proc_dump_build_key(key, prefix, "refcount"); + gf_proc_dump_write(key, "%d", fd->refcount); + gf_proc_dump_build_key(key, prefix, "flags"); + gf_proc_dump_write(key, "%d", fd->flags); + gf_proc_dump_build_key(key, prefix, "inode"); + gf_proc_dump_add_section(key); + inode_dump(inode, key, NULL); +} + + +void +fdentry_dump (fdentry_t *fdentry, char *prefix) +{ + if (!fdentry) + return; + + if (GF_FDENTRY_ALLOCATED != fdentry->next_free) + return; + + if (fdentry->fd) + fd_dump(fdentry->fd, prefix); +} + +void +fdtable_dump (fdtable_t *fdtable, char *prefix) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 0; + + if (!fdtable) + return; + + memset(key, 0, sizeof(key)); + gf_proc_dump_build_key(key, prefix, "refcount"); + gf_proc_dump_write(key, "%d", fdtable->refcount); + gf_proc_dump_build_key(key, prefix, "maxfds"); + gf_proc_dump_write(key, "%d", fdtable->max_fds); + gf_proc_dump_build_key(key, prefix, "first_free"); + gf_proc_dump_write(key, "%d", fdtable->first_free); + gf_proc_dump_build_key(key, prefix, "lock"); + gf_proc_dump_write(key, "%d", fdtable->lock); + + for ( i = 0 ; i < fdtable->max_fds; i++) { + if (GF_FDENTRY_ALLOCATED == + fdtable->fdentries[i].next_free) { + gf_proc_dump_build_key(key, prefix, "fdentry[%d]", i); + gf_proc_dump_add_section(key); + fdentry_dump(&fdtable->fdentries[i], key); + } + } +} + diff --git a/libglusterfs/src/inode.c b/libglusterfs/src/inode.c index 9796071d8..138e30068 100644 --- a/libglusterfs/src/inode.c +++ b/libglusterfs/src/inode.c @@ -24,6 +24,7 @@ #include "inode.h" #include "common-utils.h" +#include "statedump.h" #include #include #include @@ -35,6 +36,18 @@ move latest accessed dentry to list_head of inode */ +#define INODE_DUMP_LIST(head, key_buf, key_prefix, list_type, fn) \ +{ \ + int i = 1;\ + inode_t *inode = NULL;\ + list_for_each_entry (inode, head, list) {\ + gf_proc_dump_build_key(key_buf, key_prefix, "%s.%d",list_type,\ + i++);\ + gf_proc_dump_add_section(key_buf);\ + inode_dump(inode, key, fn);\ + }\ +} + static inode_t * __inode_unref (inode_t *inode); @@ -1194,3 +1207,66 @@ unlock: return ret; } + +void +inode_dump (inode_t *inode, char *prefix, inode_priv_dump_fn fn) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + int ret; + + if (!inode) + return; + + ret = TRY_LOCK(&inode->lock); + + if (ret != 0) { + gf_log("", GF_LOG_WARNING, "Unable to dump inode" + " errno: %d", errno); + return; + } + + gf_proc_dump_build_key(key, prefix, "nlookup"); + gf_proc_dump_write(key, "%ld", inode->nlookup); + gf_proc_dump_build_key(key, prefix, "generation"); + gf_proc_dump_write(key, "%ld", inode->generation); + gf_proc_dump_build_key(key, prefix, "ref"); + gf_proc_dump_write(key, "%u", inode->ref); + gf_proc_dump_build_key(key, prefix, "ino"); + gf_proc_dump_write(key, "%ld", inode->ino); + gf_proc_dump_build_key(key, prefix, "st_mode"); + gf_proc_dump_write(key, "%d", inode->st_mode); + UNLOCK(&inode->lock); + if (fn) + fn (inode); +} + +void +inode_table_dump (inode_table_t *itable, char *prefix, inode_priv_dump_fn fn) +{ + + char key[GF_DUMP_MAX_BUF_LEN]; + + if (!itable) + return; + + memset(key, 0, sizeof(key)); + gf_proc_dump_build_key(key, prefix, "hashsize"); + gf_proc_dump_write(key, "%d", itable->hashsize); + gf_proc_dump_build_key(key, prefix, "name"); + gf_proc_dump_write(key, "%s", itable->name); + + gf_proc_dump_build_key(key, prefix, "lru_limit"); + gf_proc_dump_write(key, "%d", itable->lru_limit); + gf_proc_dump_build_key(key, prefix, "active_size"); + gf_proc_dump_write(key, "%d", itable->active_size); + gf_proc_dump_build_key(key, prefix, "lru_size"); + gf_proc_dump_write(key, "%d", itable->lru_size); + gf_proc_dump_build_key(key, prefix, "purge_size"); + gf_proc_dump_write(key, "%d", itable->purge_size); + + pthread_mutex_lock(&itable->lock); + INODE_DUMP_LIST(&itable->active, key, prefix, "active", fn); + INODE_DUMP_LIST(&itable->lru, key, prefix, "lru", fn); + INODE_DUMP_LIST(&itable->purge, key, prefix, "purge", fn); +} + diff --git a/libglusterfs/src/iobuf.c b/libglusterfs/src/iobuf.c index 6d6fca133..e9408f86b 100644 --- a/libglusterfs/src/iobuf.c +++ b/libglusterfs/src/iobuf.c @@ -19,6 +19,7 @@ #include "iobuf.h" +#include "statedump.h" #include @@ -636,3 +637,106 @@ iobref_size (struct iobref *iobref) out: return size; } + +void +iobuf_info_dump (struct iobuf *iobuf, const char *key_prefix) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + struct iobuf my_iobuf; + int ret = 0; + + if (!iobuf) + return; + + memset(&my_iobuf, 0, sizeof(my_iobuf)); + + ret = TRY_LOCK(&iobuf->lock); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump iobuf" + " errno: %d", errno); + return; + } + memcpy(&my_iobuf, iobuf, sizeof(my_iobuf)); + UNLOCK(&iobuf->lock); + + gf_proc_dump_build_key(key, key_prefix,"ref"); + gf_proc_dump_write(key, "%d", my_iobuf.ref); + gf_proc_dump_build_key(key, key_prefix,"ptr"); + gf_proc_dump_write(key, "%p", my_iobuf.ptr); + +} + +void +iobuf_arena_info_dump (struct iobuf_arena *iobuf_arena, const char *key_prefix) +{ + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 1; + struct iobuf *trav; + + if (!iobuf_arena) + return; + + gf_proc_dump_build_key(key, key_prefix,"mem_base"); + gf_proc_dump_write(key, "%p", iobuf_arena->mem_base); + gf_proc_dump_build_key(key, key_prefix, "active_cnt"); + gf_proc_dump_write(key, "%d", iobuf_arena->active_cnt); + gf_proc_dump_build_key(key, key_prefix, "passive_cnt"); + gf_proc_dump_write(key, "%d", iobuf_arena->passive_cnt); + list_for_each_entry (trav, &iobuf_arena->active.list, list) { + gf_proc_dump_build_key(key, key_prefix,"active_iobuf.%d", i++); + gf_proc_dump_add_section(key); + iobuf_info_dump(trav, key); + } + + i = 1; + list_for_each_entry (trav, &iobuf_arena->passive.list, list) { + gf_proc_dump_build_key(key, key_prefix, + "passive_iobuf.%d",i++); + gf_proc_dump_add_section(key); + iobuf_info_dump(trav, key); + } + +} + +void +iobuf_stats_dump (struct iobuf_pool *iobuf_pool) +{ + + char msg[1024]; + struct iobuf_arena *trav; + int i = 1; + int ret = -1; + + if (!iobuf_pool) + return; + + memset(msg, 0, sizeof(msg)); + + ret = pthread_mutex_trylock(&iobuf_pool->mutex); + + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump iobuf pool" + " errno: %d", errno); + return; + } + gf_proc_dump_add_section("iobuf.global"); + gf_proc_dump_write("iobuf.global.iobuf_pool","%p", iobuf_pool); + gf_proc_dump_write("iobuf.global.iobuf_pool.page_size", "%d", + iobuf_pool->page_size); + gf_proc_dump_write("iobuf.global.iobuf_pool.arena_size", "%d", + iobuf_pool->arena_size); + gf_proc_dump_write("iobuf.global.iobuf_pool.arena_cnt", "%d", + iobuf_pool->arena_cnt); + + list_for_each_entry (trav, &iobuf_pool->arenas.list, list) { + snprintf(msg, sizeof(msg), "iobuf.global.iobuf_pool.arena.%d", + i); + gf_proc_dump_add_section(msg); + iobuf_arena_info_dump(trav,msg); + i++; + } + + pthread_mutex_unlock(&iobuf_pool->mutex); + + return; +} diff --git a/libglusterfs/src/iobuf.h b/libglusterfs/src/iobuf.h index d17c1db48..de95da324 100644 --- a/libglusterfs/src/iobuf.h +++ b/libglusterfs/src/iobuf.h @@ -123,5 +123,6 @@ int iobref_merge (struct iobref *to, struct iobref *from); size_t iobuf_size (struct iobuf *iobuf); size_t iobref_size (struct iobref *iobref); +void iobuf_stats_dump (struct iobuf_pool *iobuf_pool); #endif /* !_IOBUF_H_ */ diff --git a/libglusterfs/src/stack.c b/libglusterfs/src/stack.c new file mode 100644 index 000000000..453248479 --- /dev/null +++ b/libglusterfs/src/stack.c @@ -0,0 +1,171 @@ +/* + Copyright (c) 2009 Z RESEARCH, Inc. + This file is part of GlusterFS. + + GlusterFS 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 3 of the License, + or (at your option) any later version. + + GlusterFS 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, see + . +*/ + +#include "statedump.h" +#include "stack.h" + +static inline +int call_frames_count (call_frame_t *call_frame) +{ + call_frame_t *pos; + int32_t count = 0; + + if (!call_frame) + return count; + + for (pos = call_frame; pos != NULL; pos = pos->next) + count++; + + return count; +} + +void +gf_proc_dump_call_frame (call_frame_t *call_frame, const char *key_buf,...) +{ + + char prefix[GF_DUMP_MAX_BUF_LEN]; + va_list ap; + char key[GF_DUMP_MAX_BUF_LEN]; + call_frame_t my_frame; + int ret = -1; + + if (!call_frame) + return; + + assert(key_buf); + + memset(prefix, 0, sizeof(prefix)); + memset(&my_frame, 0, sizeof(my_frame)); + va_start(ap, key_buf); + vsnprintf(prefix, GF_DUMP_MAX_BUF_LEN, key_buf, ap); + va_end(ap); + + ret = TRY_LOCK(&call_frame->lock); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump call frame" + " errno: %d", errno); + return; + } + + memcpy(&my_frame, call_frame, sizeof(my_frame)); + UNLOCK(&call_frame->lock); + + gf_proc_dump_build_key(key, prefix,"ref_count"); + gf_proc_dump_write(key, "%d", my_frame.ref_count); + gf_proc_dump_build_key(key, prefix,"translator"); + gf_proc_dump_write(key, "%s", my_frame.this->name); + gf_proc_dump_build_key(key, prefix,"complete"); + gf_proc_dump_write(key, "%d", my_frame.complete); + if (my_frame.parent) { + gf_proc_dump_build_key(key, prefix,"parent"); + gf_proc_dump_write(key, "%s", my_frame.parent->this->name); + } +} + + +void +gf_proc_dump_call_stack (call_stack_t *call_stack, const char *key_buf,...) +{ + char prefix[GF_DUMP_MAX_BUF_LEN]; + va_list ap; + call_frame_t *trav; + int32_t cnt, i; + char key[GF_DUMP_MAX_BUF_LEN]; + + if (!call_stack) + return; + + assert(key_buf); + + cnt = call_frames_count(&call_stack->frames); + + memset(prefix, 0, sizeof(prefix)); + va_start(ap, key_buf); + vsnprintf(prefix, GF_DUMP_MAX_BUF_LEN, key_buf, ap); + va_end(ap); + + gf_proc_dump_build_key(key, prefix,"uid"); + gf_proc_dump_write(key, "%d", call_stack->uid); + gf_proc_dump_build_key(key, prefix,"gid"); + gf_proc_dump_write(key, "%d", call_stack->gid); + gf_proc_dump_build_key(key, prefix,"pid"); + gf_proc_dump_write(key, "%d", call_stack->pid); + gf_proc_dump_build_key(key, prefix,"unique"); + gf_proc_dump_write(key, "%Ld", call_stack->unique); + + gf_proc_dump_build_key(key, prefix,"op"); + if ((call_stack->type == GF_OP_TYPE_FOP_REQUEST) || + (call_stack->type == GF_OP_TYPE_FOP_REPLY)) { + gf_proc_dump_write(key, "%s", gf_fop_list[call_stack->op]); + } else if ((call_stack->type == GF_OP_TYPE_MOP_REQUEST) || + (call_stack->type == GF_OP_TYPE_MOP_REPLY)) { + gf_proc_dump_write(key, "%s", gf_mop_list[call_stack->op]); + } else if ((call_stack->type == GF_OP_TYPE_CBK_REQUEST) || + (call_stack->type == GF_OP_TYPE_CBK_REPLY)) { + gf_proc_dump_write(key, "%s", gf_cbk_list[call_stack->op]); + } + + gf_proc_dump_build_key(key, prefix,"type"); + gf_proc_dump_write(key, "%d", call_stack->type); + gf_proc_dump_build_key(key, prefix,"cnt"); + gf_proc_dump_write(key, "%d", cnt); + + trav = &call_stack->frames; + + for (i = 1; i <= cnt; i++) { + if (trav) { + gf_proc_dump_add_section("%s.frame.%d", prefix, i); + gf_proc_dump_call_frame(trav, "%s.frame.%d", prefix, i); + trav = trav->next; + } + } +} + +void +gf_proc_dump_pending_frames (call_pool_t *call_pool) +{ + + call_stack_t *trav = NULL; + int i = 1; + int ret = -1; + + if (!call_pool) + return; + + ret = TRY_LOCK (&(call_pool->lock)); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump call pool" + " errno: %d", errno); + return; + } + + + gf_proc_dump_add_section("global.callpool"); + gf_proc_dump_write("global.callpool","%p", call_pool); + gf_proc_dump_write("global.callpool.cnt","%d", call_pool->cnt); + + + list_for_each_entry (trav, &call_pool->all_frames, all_frames) { + gf_proc_dump_add_section("global.callpool.stack.%d",i); + gf_proc_dump_call_stack(trav, "global.callpool.stack.%d", i); + i++; + } + UNLOCK (&(call_pool->lock)); +} + diff --git a/libglusterfs/src/stack.h b/libglusterfs/src/stack.h index e7c1cbd15..942972556 100644 --- a/libglusterfs/src/stack.h +++ b/libglusterfs/src/stack.h @@ -1,4 +1,4 @@ -/* +/* Copyright (c) 2006-2009 Z RESEARCH, Inc. This file is part of GlusterFS. @@ -74,6 +74,7 @@ struct _call_frame_t { int32_t ref_count; gf_lock_t lock; void *cookie; /* unique cookie */ + gf_boolean_t complete; }; struct _call_stack_t { @@ -208,6 +209,7 @@ STACK_DESTROY (call_stack_t *stack) _parent->ref_count--; \ old_THIS = THIS; \ THIS = _parent->this; \ + frame->complete = _gf_true; \ fn (_parent, frame->cookie, _parent->this, params); \ THIS = old_THIS; \ } while (0) @@ -281,5 +283,7 @@ create_frame (xlator_t *xl, call_pool_t *pool) return &stack->frames; } +void +gf_proc_dump_pending_frames(call_pool_t *call_pool); #endif /* _STACK_H */ diff --git a/libglusterfs/src/statedump.c b/libglusterfs/src/statedump.c new file mode 100644 index 000000000..6839c28f6 --- /dev/null +++ b/libglusterfs/src/statedump.c @@ -0,0 +1,213 @@ +/* + Copyright (c) 2009 Z RESEARCH, Inc. + This file is part of GlusterFS. + + GlusterFS 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 3 of the License, + or (at your option) any later version. + + GlusterFS 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, see + . +*/ + +#include +#include +#include "glusterfs.h" +#include "logging.h" +#include "iobuf.h" +#include "statedump.h" +#include "stack.h" + + +static pthread_mutex_t gf_proc_dump_mutex; +static int gf_dump_fd = -1; + +static void +gf_proc_dump_lock (void) +{ + pthread_mutex_lock(&gf_proc_dump_mutex); +} + +static void +gf_proc_dump_unlock (void) +{ + pthread_mutex_unlock(&gf_proc_dump_mutex); +} + +static int +gf_proc_dump_open (void) +{ + char path[256]; + int dump_fd = -1; + + memset(path, 0, sizeof(path)); + snprintf(path, sizeof(path), "%s.%d",GF_DUMP_LOGFILE_ROOT, getpid()); + + dump_fd = open(path, O_CREAT|O_RDWR|O_TRUNC|O_APPEND, 0600); + if (dump_fd < 0) { + gf_log("", GF_LOG_ERROR, "Unable to open file: %s" + " errno: %d", path, errno); + return -1; + } + + gf_dump_fd = dump_fd; + return 0; +} + +static void +gf_proc_dump_close (void) +{ + close(gf_dump_fd); + gf_dump_fd = -1; +} + +void +gf_proc_dump_add_section (char *key, ...) +{ + + char buf[GF_DUMP_MAX_BUF_LEN]; + va_list ap; + int ret; + + assert(key); + + memset(buf, 0, sizeof(buf)); + snprintf(buf, GF_DUMP_MAX_BUF_LEN, "\n["); + va_start(ap, key); + vsnprintf(buf + strlen(buf), + GF_DUMP_MAX_BUF_LEN - strlen(buf), key, ap); + va_end(ap); + snprintf(buf + strlen(buf), + GF_DUMP_MAX_BUF_LEN - strlen(buf), "]\n"); + ret = write(gf_dump_fd, buf, strlen(buf)); +} + +void +gf_proc_dump_write (char *key, char *value,...) +{ + + char buf[GF_DUMP_MAX_BUF_LEN]; + int offset = 0; + va_list ap; + int ret; + + offset = strlen(key); + + memset(buf, 0, GF_DUMP_MAX_BUF_LEN); + snprintf(buf, GF_DUMP_MAX_BUF_LEN, "%s",key); + snprintf(buf + offset, GF_DUMP_MAX_BUF_LEN - offset, "="); + offset += 1; + va_start(ap, value); + vsnprintf(buf + offset, GF_DUMP_MAX_BUF_LEN - offset, value, ap); + va_end(ap); + + offset = strlen(buf); + snprintf(buf + offset, GF_DUMP_MAX_BUF_LEN - offset, "\n"); + ret = write(gf_dump_fd, buf, strlen(buf)); +} + + +/* Currently this dumps only mallinfo. More can be built on here */ +void +gf_proc_dump_mem_info () +{ +#ifdef HAVE_MALLOC_STATS + struct mallinfo info; + + memset(&info, 0, sizeof(struct mallinfo)); + info = mallinfo(); + + gf_proc_dump_add_section("mallinfo"); + gf_proc_dump_write("mallinfo_arena", "%d", info.arena); + gf_proc_dump_write("mallinfo_ordblks", "%d", info.ordblks); + gf_proc_dump_write("mallinfo_smblks","%d", info.smblks); + gf_proc_dump_write("mallinfo_hblks","%d", info.hblks); + gf_proc_dump_write("mallinfo_hblkhd", "%d", info.hblkhd); + gf_proc_dump_write("mallinfo_usmblks","%d", info.usmblks); + gf_proc_dump_write("mallinfo_fsmblks","%d", info.fsmblks); + gf_proc_dump_write("mallinfo_uordblks","%d", info.uordblks); + gf_proc_dump_write("mallinfo_fordblks", "%d", info.fordblks); + gf_proc_dump_write("mallinfo_keepcost", "%d", info.keepcost); +#endif + +} + + +void +gf_proc_dump_xlator_info (xlator_t *this_xl) +{ + + if (!this_xl) + return; + + while (this_xl) { + if (!this_xl->dumpops) { + this_xl = this_xl->next; + continue; + } + if (this_xl->dumpops->priv) + this_xl->dumpops->priv(this_xl); + if (this_xl->dumpops->inode) + this_xl->dumpops->inode(this_xl); + if (this_xl->dumpops->fd) + this_xl->dumpops->fd(this_xl); + this_xl = this_xl->next; + } + + return; +} + + +void +gf_proc_dump_info (int signum) +{ + int ret = -1; + glusterfs_ctx_t *ctx = NULL; + + gf_proc_dump_lock(); + ret = gf_proc_dump_open(); + if (ret < 0) + goto out; + gf_proc_dump_mem_info(); + ctx = get_global_ctx_ptr(); + if (ctx) { + iobuf_stats_dump(ctx->iobuf_pool); + gf_proc_dump_pending_frames(ctx->pool); + gf_proc_dump_xlator_info(ctx->graph); + } + + gf_proc_dump_close(); +out: + gf_proc_dump_unlock(); + + return; +} + +void +gf_proc_dump_fini (void) +{ + pthread_mutex_destroy(&gf_proc_dump_mutex); +} + + +void +gf_proc_dump_init () +{ + pthread_mutex_init(&gf_proc_dump_mutex, NULL); + + return; +} + +void +gf_proc_dump_cleanup (void) +{ + pthread_mutex_destroy(&gf_proc_dump_mutex); +} + diff --git a/libglusterfs/src/statedump.h b/libglusterfs/src/statedump.h new file mode 100644 index 000000000..9ac50ec0c --- /dev/null +++ b/libglusterfs/src/statedump.h @@ -0,0 +1,78 @@ +/* + Copyright (c) 2009 Z RESEARCH, Inc. + This file is part of GlusterFS. + + GlusterFS 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 3 of the License, + or (at your option) any later version. + + GlusterFS 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, see + . +*/ + + +#ifndef STATEDUMP_H +#define STATEDUMP_H + +#include +#include "inode.h" + +#define GF_DUMP_MAX_BUF_LEN 4096 + +#define GF_DUMP_LOGFILE_ROOT "/tmp/glusterdump" +#define GF_DUMP_LOGFILE_ROOT_LEN 256 + +static inline +void _gf_proc_dump_build_key (char *key, const char *prefix, char *fmt,...) +{ + char buf[GF_DUMP_MAX_BUF_LEN]; + va_list ap; + + memset(buf, 0, sizeof(buf)); + va_start(ap, fmt); + vsnprintf(buf, GF_DUMP_MAX_BUF_LEN, fmt, ap); + va_end(ap); + snprintf(key, GF_DUMP_MAX_BUF_LEN, "%s.%s", prefix, buf); +} + +#define gf_proc_dump_build_key(key, key_prefix, fmt...) \ +{\ + _gf_proc_dump_build_key(key, key_prefix, ##fmt);\ +} + +typedef void (*inode_priv_dump_fn) (inode_t *); + +void +gf_proc_dump_init(); + +void +gf_proc_dump_fini(void); + +void +gf_proc_dump_cleanup(void); + +void +gf_proc_dump_info(int signum); + +void +gf_proc_dump_add_section(char *key,...); + +void +gf_proc_dump_write(char *key, char *value,...); + +void +inode_table_dump(inode_table_t *itable, char *prefix, inode_priv_dump_fn fn); + +void +fdtable_dump(fdtable_t *fdtable, char *prefix); + +void +inode_dump(inode_t *inode, char *prefix, inode_priv_dump_fn fn); +#endif /* STATEDUMP_H */ diff --git a/libglusterfs/src/xlator.c b/libglusterfs/src/xlator.c index a3f8ea8fc..def1ad1df 100644 --- a/libglusterfs/src/xlator.c +++ b/libglusterfs/src/xlator.c @@ -740,6 +740,11 @@ xlator_set_type (xlator_t *xl, "dlsym(notify) on %s -- neglecting", dlerror ()); } + if (!(xl->dumpops = dlsym (handle, "dumpops"))) { + gf_log ("xlator", GF_LOG_DEBUG, + "dlsym(dumpops) on %s -- neglecting", dlerror ()); + } + INIT_LIST_HEAD (&xl->volume_options); vol_opt = CALLOC (1, sizeof (volume_opt_list_t)); diff --git a/libglusterfs/src/xlator.h b/libglusterfs/src/xlator.h index e8fc9d250..2e815af91 100644 --- a/libglusterfs/src/xlator.h +++ b/libglusterfs/src/xlator.h @@ -806,6 +806,19 @@ struct xlator_cbks { cbk_release_t releasedir; }; +typedef int32_t (*dumpop_priv_t) (xlator_t *this); + +typedef int32_t (*dumpop_inode_t) (xlator_t *this); + +typedef int32_t (*dumpop_fd_t) (xlator_t *this); + + +struct xlator_dumpops { + dumpop_priv_t priv; + dumpop_inode_t inode; + dumpop_fd_t fd; +}; + typedef struct xlator_list { xlator_t *xlator; struct xlator_list *next; @@ -859,10 +872,11 @@ struct _xlator { dict_t *options; /* Set after doing dlopen() */ - struct xlator_fops *fops; - struct xlator_mops *mops; - struct xlator_cbks *cbks; - struct list_head volume_options; /* list of volume_option_t */ + struct xlator_fops *fops; + struct xlator_mops *mops; + struct xlator_cbks *cbks; + struct xlator_dumpops *dumpops; + struct list_head volume_options; /* list of volume_option_t */ void (*fini) (xlator_t *this); int32_t (*init) (xlator_t *this); -- cgit