summaryrefslogtreecommitdiffstats
path: root/libglusterfs/src/stack.c
diff options
context:
space:
mode:
Diffstat (limited to 'libglusterfs/src/stack.c')
-rw-r--r--libglusterfs/src/stack.c432
1 files changed, 432 insertions, 0 deletions
diff --git a/libglusterfs/src/stack.c b/libglusterfs/src/stack.c
new file mode 100644
index 000000000..37b338f51
--- /dev/null
+++ b/libglusterfs/src/stack.c
@@ -0,0 +1,432 @@
+/*
+ Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
+ This file is part of GlusterFS.
+
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
+*/
+
+#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;
+}
+
+call_frame_t *
+create_frame (xlator_t *xl, call_pool_t *pool)
+{
+ call_stack_t *stack = NULL;
+
+ if (!xl || !pool) {
+ return NULL;
+ }
+
+ stack = mem_get0 (pool->stack_mem_pool);
+ if (!stack)
+ return NULL;
+
+ stack->pool = pool;
+ stack->frames.root = stack;
+ stack->frames.this = xl;
+ stack->ctx = xl->ctx;
+
+ if (stack->ctx->measure_latency) {
+ if (gettimeofday (&stack->tv, NULL) == -1)
+ gf_log ("stack", GF_LOG_ERROR, "gettimeofday () failed."
+ " (%s)", strerror (errno));
+ memcpy (&stack->frames.begin, &stack->tv, sizeof (stack->tv));
+ }
+
+ LOCK (&pool->lock);
+ {
+ list_add (&stack->all_frames, &pool->all_frames);
+ pool->cnt++;
+ }
+ UNLOCK (&pool->lock);
+
+ LOCK_INIT (&stack->frames.lock);
+ LOCK_INIT (&stack->stack_lock);
+
+ return &stack->frames;
+}
+
+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;
+ call_frame_t my_frame;
+ int ret = -1;
+ char timestr[256] = {0,};
+
+ if (!call_frame)
+ return;
+
+ GF_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)
+ goto out;
+
+ memcpy(&my_frame, call_frame, sizeof(my_frame));
+ UNLOCK(&call_frame->lock);
+
+ if (my_frame.this->ctx->measure_latency) {
+ gf_time_fmt (timestr, sizeof timestr, my_frame.begin.tv_sec,
+ gf_timefmt_FT);
+ snprintf (timestr + strlen (timestr),
+ sizeof timestr - strlen (timestr),
+ ".%"GF_PRI_SUSECONDS, my_frame.begin.tv_usec);
+ gf_proc_dump_write("frame-creation-time", "%s", timestr);
+ }
+
+ gf_proc_dump_write("ref_count", "%d", my_frame.ref_count);
+ gf_proc_dump_write("translator", "%s", my_frame.this->name);
+ gf_proc_dump_write("complete", "%d", my_frame.complete);
+ if (my_frame.parent)
+ gf_proc_dump_write("parent", "%s", my_frame.parent->this->name);
+
+ if (my_frame.wind_from)
+ gf_proc_dump_write("wind_from", "%s", my_frame.wind_from);
+
+ if (my_frame.wind_to)
+ gf_proc_dump_write("wind_to", "%s", my_frame.wind_to);
+
+ if (my_frame.unwind_from)
+ gf_proc_dump_write("unwind_from", "%s", my_frame.unwind_from);
+
+ if (my_frame.unwind_to)
+ gf_proc_dump_write("unwind_to", "%s", my_frame.unwind_to);
+
+ ret = 0;
+out:
+ if (ret) {
+ gf_proc_dump_write("Unable to dump the frame information",
+ "(Lock acquisition failed) %p", my_frame);
+ return;
+ }
+}
+
+
+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 timestr[256] = {0,};
+
+ if (!call_stack)
+ return;
+
+ GF_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);
+
+ if (call_stack->ctx->measure_latency) {
+ gf_time_fmt (timestr, sizeof timestr, call_stack->tv.tv_sec,
+ gf_timefmt_FT);
+ snprintf (timestr + strlen (timestr),
+ sizeof timestr - strlen (timestr),
+ ".%"GF_PRI_SUSECONDS, call_stack->tv.tv_usec);
+ gf_proc_dump_write("callstack-creation-time", "%s", timestr);
+ }
+
+ gf_proc_dump_write("uid", "%d", call_stack->uid);
+ gf_proc_dump_write("gid", "%d", call_stack->gid);
+ gf_proc_dump_write("pid", "%d", call_stack->pid);
+ gf_proc_dump_write("unique", "%Ld", call_stack->unique);
+ gf_proc_dump_write("lk-owner", "%s", lkowner_utoa (&call_stack->lk_owner));
+
+ if (call_stack->type == GF_OP_TYPE_FOP)
+ gf_proc_dump_write("op", "%s",
+ (char *)gf_fop_list[call_stack->op]);
+ else
+ gf_proc_dump_write("op", "stack");
+
+ gf_proc_dump_write("type", "%d", call_stack->type);
+ gf_proc_dump_write("cnt", "%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;
+ gf_boolean_t section_added = _gf_true;
+
+ if (!call_pool)
+ return;
+
+ ret = TRY_LOCK (&(call_pool->lock));
+ if (ret)
+ goto out;
+
+
+ gf_proc_dump_add_section("global.callpool");
+ section_added = _gf_true;
+ gf_proc_dump_write("callpool_address","%p", call_pool);
+ gf_proc_dump_write("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));
+
+ ret = 0;
+out:
+ if (ret) {
+ if (_gf_false == section_added)
+ gf_proc_dump_add_section("global.callpool");
+ gf_proc_dump_write("Unable to dump the callpool",
+ "(Lock acquisition failed) %p",
+ call_pool);
+ }
+ return;
+}
+
+void
+gf_proc_dump_call_frame_to_dict (call_frame_t *call_frame,
+ char *prefix, dict_t *dict)
+{
+ int ret = -1;
+ char key[GF_DUMP_MAX_BUF_LEN] = {0,};
+ call_frame_t tmp_frame = {0,};
+
+ if (!call_frame || !dict)
+ return;
+
+ ret = TRY_LOCK (&call_frame->lock);
+ if (ret)
+ return;
+ memcpy (&tmp_frame, call_frame, sizeof (tmp_frame));
+ UNLOCK (&call_frame->lock);
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.refcount", prefix);
+ ret = dict_set_int32 (dict, key, tmp_frame.ref_count);
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.translator", prefix);
+ ret = dict_set_dynstr (dict, key, gf_strdup (tmp_frame.this->name));
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.complete", prefix);
+ ret = dict_set_int32 (dict, key, tmp_frame.complete);
+ if (ret)
+ return;
+
+ if (tmp_frame.parent) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.parent", prefix);
+ ret = dict_set_dynstr (dict, key,
+ gf_strdup (tmp_frame.parent->this->name));
+ if (ret)
+ return;
+ }
+
+ if (tmp_frame.wind_from) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.windfrom", prefix);
+ ret = dict_set_dynstr (dict, key,
+ gf_strdup (tmp_frame.wind_from));
+ if (ret)
+ return;
+ }
+
+ if (tmp_frame.wind_to) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.windto", prefix);
+ ret = dict_set_dynstr (dict, key,
+ gf_strdup (tmp_frame.wind_to));
+ if (ret)
+ return;
+ }
+
+ if (tmp_frame.unwind_from) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.unwindfrom", prefix);
+ ret = dict_set_dynstr (dict, key,
+ gf_strdup (tmp_frame.unwind_from));
+ if (ret)
+ return;
+ }
+
+ if (tmp_frame.unwind_to) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.unwind_to", prefix);
+ ret = dict_set_dynstr (dict, key,
+ gf_strdup (tmp_frame.unwind_to));
+ }
+
+ return;
+}
+
+void
+gf_proc_dump_call_stack_to_dict (call_stack_t *call_stack,
+ char *prefix, dict_t *dict)
+{
+ int ret = -1;
+ char key[GF_DUMP_MAX_BUF_LEN] = {0,};
+ call_frame_t *trav = NULL;
+ int count = 0;
+ int i = 0;
+
+ if (!call_stack || !dict)
+ return;
+
+ count = call_frames_count (&call_stack->frames);
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.uid", prefix);
+ ret = dict_set_int32 (dict, key, call_stack->uid);
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.gid", prefix);
+ ret = dict_set_int32 (dict, key, call_stack->gid);
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.pid", prefix);
+ ret = dict_set_int32 (dict, key, call_stack->pid);
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.unique", prefix);
+ ret = dict_set_uint64 (dict, key, call_stack->unique);
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.op", prefix);
+ if (call_stack->type == GF_OP_TYPE_FOP)
+ ret = dict_set_str (dict, key,
+ (char *)gf_fop_list[call_stack->op]);
+ else
+ ret = dict_set_str (dict, key, "other");
+
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.type", prefix);
+ ret = dict_set_int32 (dict, key, call_stack->type);
+ if (ret)
+ return;
+
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.count", prefix);
+ ret = dict_set_int32 (dict, key, count);
+ if (ret)
+ return;
+
+ trav = &call_stack->frames;
+ for (i = 0; i < count; i++) {
+ if (trav) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "%s.frame%d",
+ prefix, i);
+ gf_proc_dump_call_frame_to_dict (trav, key, dict);
+ trav = trav->next;
+ }
+ }
+
+ return;
+}
+
+void
+gf_proc_dump_pending_frames_to_dict (call_pool_t *call_pool, dict_t *dict)
+{
+ int ret = -1;
+ call_stack_t *trav = NULL;
+ char key[GF_DUMP_MAX_BUF_LEN] = {0,};
+ int i = 0;
+
+ if (!call_pool || !dict)
+ return;
+
+ ret = TRY_LOCK (&call_pool->lock);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_WARNING, "Unable to dump call pool"
+ " to dict. errno: %d", errno);
+ return;
+ }
+
+ ret = dict_set_int32 (dict, "callpool.count", call_pool->cnt);
+ if (ret)
+ goto out;
+
+ list_for_each_entry (trav, &call_pool->all_frames, all_frames) {
+ memset (key, 0, sizeof (key));
+ snprintf (key, sizeof (key), "callpool.stack%d", i);
+ gf_proc_dump_call_stack_to_dict (trav, key, dict);
+ i++;
+ }
+
+out:
+ UNLOCK (&call_pool->lock);
+
+ return;
+}
+
+gf_boolean_t
+__is_fuse_call (call_frame_t *frame)
+{
+ gf_boolean_t is_fuse_call = _gf_false;
+ GF_ASSERT (frame);
+ GF_ASSERT (frame->root);
+
+ if (NFS_PID != frame->root->pid)
+ is_fuse_call = _gf_true;
+ return is_fuse_call;
+}