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 --- glusterfsd/src/glusterfsd.c | 4 +- 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 ++- xlators/cluster/afr/src/afr.c | 59 +++++++ xlators/features/locks/src/posix.c | 55 +++++++ xlators/protocol/server/src/server-protocol.c | 81 ++++++++++ xlators/storage/posix/src/posix.c | 45 ++++++ 16 files changed, 983 insertions(+), 8 deletions(-) create mode 100644 libglusterfs/src/stack.c create mode 100644 libglusterfs/src/statedump.c create mode 100644 libglusterfs/src/statedump.h diff --git a/glusterfsd/src/glusterfsd.c b/glusterfsd/src/glusterfsd.c index 3c9e77822..7be544957 100644 --- a/glusterfsd/src/glusterfsd.c +++ b/glusterfsd/src/glusterfsd.c @@ -62,6 +62,7 @@ #include "common-utils.h" #include "event.h" #include "globals.h" +#include "statedump.h" #include @@ -1157,6 +1158,7 @@ main (int argc, char *argv[]) return -1; } gf_log_set_loglevel (cmd_args->log_level); + gf_proc_dump_init(); /* setting up environment */ lim.rlim_cur = RLIM_INFINITY; @@ -1169,7 +1171,7 @@ main (int argc, char *argv[]) #ifdef DEBUG mtrace (); #endif - signal (SIGUSR1, (sighandler_t) malloc_stats); + signal (SIGUSR1, (sighandler_t) gf_proc_dump_info); #endif signal (SIGSEGV, gf_print_trace); signal (SIGABRT, gf_print_trace); 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); diff --git a/xlators/cluster/afr/src/afr.c b/xlators/cluster/afr/src/afr.c index 6b3b05c6b..6b7b007ae 100644 --- a/xlators/cluster/afr/src/afr.c +++ b/xlators/cluster/afr/src/afr.c @@ -43,6 +43,7 @@ #include "compat-errno.h" #include "compat.h" #include "byte-order.h" +#include "statedump.h" #include "fd.h" @@ -2158,6 +2159,60 @@ out: return 0; } +int +afr_priv_dump (xlator_t *this) +{ + afr_private_t *priv = NULL; + char key_prefix[GF_DUMP_MAX_BUF_LEN]; + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 0; + + + assert(this); + priv = this->private; + + assert(priv); + snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.%s", this->type, this->name); + gf_proc_dump_add_section(key_prefix); + gf_proc_dump_build_key(key, key_prefix, "child_count"); + gf_proc_dump_write(key, "%u", priv->child_count); + gf_proc_dump_build_key(key, key_prefix, "read_child_rr"); + gf_proc_dump_write(key, "%u", priv->read_child_rr); + for (i = 0; i < priv->child_count; i++) { + gf_proc_dump_build_key(key, key_prefix, "child_up[%d]", i); + gf_proc_dump_write(key, "%d", priv->child_up[i]); + gf_proc_dump_build_key(key, key_prefix, + "pending_key[%d]", i); + gf_proc_dump_write(key, "%s", priv->pending_key[i]); + } + gf_proc_dump_build_key(key, key_prefix, "data_self_heal"); + gf_proc_dump_write(key, "%d", priv->data_self_heal); + gf_proc_dump_build_key(key, key_prefix, "metadata_self_heal"); + gf_proc_dump_write(key, "%d", priv->metadata_self_heal); + gf_proc_dump_build_key(key, key_prefix, "entry_self_heal"); + gf_proc_dump_write(key, "%d", priv->entry_self_heal); + gf_proc_dump_build_key(key, key_prefix, "data_change_log"); + gf_proc_dump_write(key, "%d", priv->data_change_log); + gf_proc_dump_build_key(key, key_prefix, "metadata_change_log"); + gf_proc_dump_write(key, "%d", priv->metadata_change_log); + gf_proc_dump_build_key(key, key_prefix, "entry_change_log"); + gf_proc_dump_write(key, "%d", priv->entry_change_log); + gf_proc_dump_build_key(key, key_prefix, "read_child"); + gf_proc_dump_write(key, "%d", priv->read_child); + gf_proc_dump_build_key(key, key_prefix, "favorite_child"); + gf_proc_dump_write(key, "%u", priv->favorite_child); + gf_proc_dump_build_key(key, key_prefix, "data_lock_server_count"); + gf_proc_dump_write(key, "%u", priv->data_lock_server_count); + gf_proc_dump_build_key(key, key_prefix, "metadata_lock_server_count"); + gf_proc_dump_write(key, "%u", priv->metadata_lock_server_count); + gf_proc_dump_build_key(key, key_prefix, "entry_lock_server_count"); + gf_proc_dump_write(key, "%u", priv->entry_lock_server_count); + gf_proc_dump_build_key(key, key_prefix, "wait_count"); + gf_proc_dump_write(key, "%u", priv->wait_count); + + return 0; +} + /** * find_child_index - find the child's index in the array of subvolumes @@ -2587,6 +2642,10 @@ struct xlator_fops fops = { struct xlator_mops mops = { }; +struct xlator_dumpops dumpops = { + .priv = afr_priv_dump, +}; + struct xlator_cbks cbks = { .release = afr_release, diff --git a/xlators/features/locks/src/posix.c b/xlators/features/locks/src/posix.c index d672beaeb..7389e1e6a 100644 --- a/xlators/features/locks/src/posix.c +++ b/xlators/features/locks/src/posix.c @@ -36,6 +36,7 @@ #include "locks.h" #include "common.h" +#include "statedump.h" #ifndef LLONG_MAX #define LLONG_MAX LONG_LONG_MAX /* compat with old gcc */ @@ -768,6 +769,57 @@ pl_forget (xlator_t *this, } +void +pl_dump_inode_priv (inode_t *inode) +{ + + int ret = -1; + uint64_t tmp_pl_inode = 0; + pl_inode_t *pl_inode = NULL; + char key[GF_DUMP_MAX_BUF_LEN]; + + if (!inode) + return; + + ret = inode_ctx_get (inode, inode->table->xl, &tmp_pl_inode); + + if (ret != 0) + return; + + pl_inode = (pl_inode_t *)(long)tmp_pl_inode; + + if (!pl_inode) + return; + + gf_proc_dump_build_key(key, + "xlator.feature.locks.inode", + "%ld.%s",inode->ino, "mandatory"); + gf_proc_dump_write(key, "%d", pl_inode->mandatory); +} + + + +/* + * pl_dump_inode - inode dump function for posix locks + * + */ +int +pl_dump_inode (xlator_t *this) +{ + + assert(this); + + if (this->itable) { + inode_table_dump(this->itable, + "xlator.features.locks.inode_table", + pl_dump_inode_priv); + } + + return 0; +} + + + int init (xlator_t *this) { @@ -864,6 +916,9 @@ struct xlator_fops fops = { struct xlator_mops mops = { }; +struct xlator_dumpops dumpops = { + .inode = pl_dump_inode, +}; struct xlator_cbks cbks = { .forget = pl_forget, diff --git a/xlators/protocol/server/src/server-protocol.c b/xlators/protocol/server/src/server-protocol.c index 220f5b3b4..47a6f0277 100644 --- a/xlators/protocol/server/src/server-protocol.c +++ b/xlators/protocol/server/src/server-protocol.c @@ -40,6 +40,7 @@ #include "dict.h" #include "compat.h" #include "compat-errno.h" +#include "statedump.h" static void @@ -7512,7 +7513,80 @@ server_nop_cbk (call_frame_t *frame, void *cookie, xlator_t *this, return 0; } +/* + * server_fd - fdtable dump function for server protocol + * @this: + * + */ +int +server_fd (xlator_t *this) +{ + server_conf_t *conf = NULL; + server_connection_t *trav = NULL; + char key[GF_DUMP_MAX_BUF_LEN]; + int i = 1; + int ret = -1; + + if (!this) + return -1; + + conf = this->private; + if (!conf) { + gf_log (this->name, GF_LOG_WARNING, + "conf null in xlator"); + return -1; + } + + gf_proc_dump_add_section("xlator.protocol.server.conn"); + + ret = pthread_mutex_trylock (&conf->mutex); + if (ret) { + gf_log("", GF_LOG_WARNING, "Unable to dump fdtable" + " errno: %d", errno); + return -1; + } + + list_for_each_entry (trav, &conf->conns, list) { + if (trav->id) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.id", i); + gf_proc_dump_write(key, "%s", trav->id); + } + + gf_proc_dump_build_key(key,"xlator.protocol.server.conn", + "%d.ref",i) + gf_proc_dump_write(key, "%d", trav->ref); + if (trav->bound_xl) { + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.bound_xl", i); + gf_proc_dump_write(key, "%s", trav->bound_xl->name); + } + + gf_proc_dump_build_key(key, + "xlator.protocol.server.conn", + "%d.id", i); + fdtable_dump(trav->fdtable,key); + i++; + } + pthread_mutex_unlock (&conf->mutex); + + + return 0; + } + +int +server_priv (xlator_t *this) +{ + return 0; +} +int +server_inode (xlator_t *this) +{ + return 0; +} static void get_auth_types (dict_t *this, char *key, data_t *value, void *data) { @@ -7841,6 +7915,13 @@ struct xlator_fops fops = { struct xlator_cbks cbks = { }; +struct xlator_dumpops dumpops = { + .inode = server_inode, + .priv = server_priv, + .fd = server_fd, +}; + + struct volume_options options[] = { { .key = {"transport-type"}, .value = {"tcp", "socket", "ib-verbs", "unix", "ib-sdp", diff --git a/xlators/storage/posix/src/posix.c b/xlators/storage/posix/src/posix.c index 4bcea07f9..b124d1362 100644 --- a/xlators/storage/posix/src/posix.c +++ b/xlators/storage/posix/src/posix.c @@ -45,6 +45,7 @@ #include "compat.h" #include "byte-order.h" #include "syscall.h" +#include "statedump.h" #undef HAVE_SET_FSID #ifdef HAVE_SET_FSID @@ -3808,6 +3809,45 @@ posix_checksum (call_frame_t *frame, xlator_t *this, return 0; } +int32_t +posix_priv (xlator_t *this) +{ + struct posix_private *priv = NULL; + char key_prefix[GF_DUMP_MAX_BUF_LEN]; + char key[GF_DUMP_MAX_BUF_LEN]; + + snprintf(key_prefix, GF_DUMP_MAX_BUF_LEN, "%s.%s", this->type, + this->name); + gf_proc_dump_add_section(key_prefix); + + if (!this) + return 0; + + priv = this->private; + + if (!priv) + return 0; + + gf_proc_dump_build_key(key, key_prefix, "base_path"); + gf_proc_dump_write(key,"%s", priv->base_path); + gf_proc_dump_build_key(key, key_prefix, "base_path_length"); + gf_proc_dump_write(key,"%d", priv->base_path_length); + gf_proc_dump_build_key(key, key_prefix, "max_read"); + gf_proc_dump_write(key,"%d", priv->max_read); + gf_proc_dump_build_key(key, key_prefix, "max_write"); + gf_proc_dump_write(key,"%d", priv->max_write); + gf_proc_dump_build_key(key, key_prefix, "stats.nr_files"); + gf_proc_dump_write(key,"%ld", priv->stats.nr_files); + + return 0; +} + +int32_t +posix_inode (xlator_t *this) +{ + return 0; +} + /** * notify - when parent sends PARENT_UP, send CHILD_UP event from here */ @@ -4056,6 +4096,11 @@ fini (xlator_t *this) return; } +struct xlator_dumpops dumpops = { + .priv = posix_priv, + .inode = posix_inode, +}; + struct xlator_mops mops = { .stats = posix_stats, }; -- cgit