From 45172a5415abc6b2f17eea74d51805ac85cc0072 Mon Sep 17 00:00:00 2001 From: Kaushal M Date: Mon, 5 Sep 2011 14:33:43 +0530 Subject: cli : new volume statedump command Changes: 1. Add a new 'volume statedump' command, that performs statedumps of all the bricks in the volume and saves them in a specified location. 2. Add new server option 'server.statedump-path'. 3. Remove multiple function definitions in glusterd.h Statedump Information: The 'volume statedump' command performs statedumps on all the bricks in a given volume. The syntax of the command is, gluster volume statedump [type]...... Types include, * all * mem * iobuf * callpool * priv * fd * inode Defaults to 'all' when no type is specified. The statedump files are created by default in /tmp directory of the server on which the bricks are present. This path can be changed by setting the 'server.statedump-path' option. The statedump files will be named as, ..dump Change-Id: I01c0e1a8aad490da818e086d89f292bd2ed06fd4 BUG: 1964 Reviewed-on: http://review.gluster.com/321 Tested-by: Gluster Build System Reviewed-by: Amar Tumballi --- cli/src/cli-cmd-parser.c | 55 ++++++++ cli/src/cli-cmd-volume.c | 70 +++++++++++ cli/src/cli-rpc-ops.c | 72 ++++++++++- cli/src/cli.h | 4 + libglusterfs/src/common-utils.c | 18 +++ libglusterfs/src/common-utils.h | 13 ++ libglusterfs/src/glusterfs.h | 1 + libglusterfs/src/statedump.c | 112 +++++++++-------- libglusterfs/src/statedump.h | 5 - rpc/rpc-lib/src/protocol-common.h | 1 + rpc/xdr/src/cli1-xdr.c | 34 +++++ rpc/xdr/src/cli1-xdr.h | 23 ++++ rpc/xdr/src/cli1-xdr.x | 15 ++- xlators/mgmt/glusterd/src/glusterd-handler.c | 4 +- xlators/mgmt/glusterd/src/glusterd-op-sm.c | 35 ++++-- xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 14 +++ xlators/mgmt/glusterd/src/glusterd-utils.c | 109 ++++++++++++++++ xlators/mgmt/glusterd/src/glusterd-utils.h | 5 + xlators/mgmt/glusterd/src/glusterd-volgen.c | 1 + xlators/mgmt/glusterd/src/glusterd-volume-ops.c | 161 ++++++++++++++++++++++++ xlators/mgmt/glusterd/src/glusterd.h | 20 ++- xlators/protocol/server/src/server.c | 45 ++++++- 22 files changed, 732 insertions(+), 85 deletions(-) diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 6d984680e35..d3cb1240fe7 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -1731,3 +1731,58 @@ cli_cmd_volume_status_parse (const char **words, int wordcount, return ret; } + +gf_boolean_t +cli_cmd_validate_dumpoption (const char *option) +{ + char *opwords[] = {"all", "mem", "iobuf", "callpool", "priv", "fd", + "inode", NULL}; + char *w = NULL; + + w = str_getunamb (option, opwords); + if (!w) { + gf_log ("cli", GF_LOG_DEBUG, "Unknown statedump option %s", + option); + return _gf_false; + } + return _gf_true; +} + +int +cli_cmd_volume_statedump_options_parse (const char **words, int wordcount, + dict_t **options) +{ + int ret = 0; + int i = 0; + dict_t *dict = NULL; + int option_cnt = 0; + char option_str[100] = {0,}; + + for (i = 3; i < wordcount; i++, option_cnt++) { + if (!cli_cmd_validate_dumpoption (words[i])) { + ret = -1; + goto out; + } + strncat (option_str, words[i], sizeof (words [i])); + strncat (option_str, " ", 1); + } + dict = dict_new (); + if (!dict) + goto out; + + ret = dict_set_str (dict, "options", gf_strdup (option_str)); + if (ret) + goto out; + + ret = dict_set_int32 (dict, "option-cnt", option_cnt); + if (ret) + goto out; + + *options = dict; +out: + if (ret && dict) + dict_destroy (dict); + if (ret) + gf_log ("cli", GF_LOG_ERROR, "Error parsing dumpoptions"); + return ret; +} diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 00077253237..9b85bf819c1 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1510,6 +1510,72 @@ out: return ret; } +int +cli_cmd_volume_statedump_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + if (wordcount < 3) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + if (wordcount > 3) { + ret = cli_cmd_volume_statedump_options_parse (words, wordcount, + &options); + if (ret) { + parse_error = 1; + gf_log ("cli", GF_LOG_ERROR, "Error parsing " + "statedump options"); + cli_out ("Error parsing options"); + cli_usage_out (word->pattern); + } + } else { + options = dict_new (); + if (!options) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Could not create dict"); + goto out; + } + ret = dict_set_str (options, "options",""); + if (ret) + goto out; + ret = dict_set_int32 (options, "option-cnt", 0); + if (ret) + goto out; + } + + ret = dict_set_str (options, "volname", (char *)words[2]); + if (ret) + goto out; + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_STATEDUMP_VOLUME]; + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error = 0)) + cli_out ("Volume statedump failed"); + } + + return ret; +} + + struct cli_cmd volume_cmds[] = { { "volume info [all|]", cli_cmd_volume_info_cbk, @@ -1616,6 +1682,10 @@ struct cli_cmd volume_cmds[] = { cli_cmd_volume_heal_cbk, "Start healing of volume specified by "}, + {"volume statedump [all|mem|iobuf|callpool|priv|fd|inode]...", + cli_cmd_volume_statedump_cbk, + "perform statedump on bricks"}, + { NULL, NULL, NULL } }; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index b58e0317363..1e77ae0ab71 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -4000,7 +4000,76 @@ out: return ret; } +int32_t +gf_cli3_1_statedump_volume_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf1_cli_statedump_vol_rsp rsp = {0,}; + int ret = -1; + + if (-1 == req->rpc_status) + goto out; + ret = xdr_to_generic (*iov, &rsp, + (xdrproc_t)xdr_gf1_cli_statedump_vol_rsp); + if (ret < 0) { + gf_log (THIS->name, GF_LOG_ERROR, "XDR decoding failed"); + goto out; + } + gf_log ("cli", GF_LOG_DEBUG, "Recieved response to statedump"); + if (rsp.op_ret) + cli_out ("%s", rsp.op_errstr); + else + cli_out ("Volume statedump sucessful"); + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + return ret; +} + +int32_t +gf_cli3_1_statedump_volume (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf1_cli_statedump_vol_req req = {0,}; + dict_t *options = NULL; + char *volname = NULL; + char *option_str = NULL; + int option_cnt = 0; + int ret = -1; + + if (!frame || !this || !data) + goto out; + + options = data; + + ret = dict_get_str (options, "volname", &volname); + if (ret) + goto out; + req.volname = volname; + + ret = dict_get_str (options, "options", &option_str); + if (ret) + goto out; + req.options = option_str; + + ret = dict_get_int32 (options, "option-cnt", &option_cnt); + if (ret) + goto out; + req.option_cnt = option_cnt; + ret = cli_cmd_submit (&req, frame, cli_rpc_prog, + GLUSTER_CLI_STATEDUMP_VOLUME, NULL, + this, gf_cli3_1_statedump_volume_cbk, + (xdrproc_t)xdr_gf1_cli_statedump_vol_req); + +out: + if (options) + dict_destroy (options); + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_NULL] = {"NULL", NULL }, @@ -4036,7 +4105,8 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_STATUS_VOLUME] = {"STATUS_VOLUME", gf_cli3_1_status_volume}, [GLUSTER_CLI_MOUNT] = {"MOUNT", gf_cli3_1_mount}, [GLUSTER_CLI_UMOUNT] = {"UMOUNT", gf_cli3_1_umount}, - [GLUSTER_CLI_HEAL_VOLUME] = {"HEAL_VOLUME", gf_cli3_1_heal_volume} + [GLUSTER_CLI_HEAL_VOLUME] = {"HEAL_VOLUME", gf_cli3_1_heal_volume}, + [GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", gf_cli3_1_statedump_volume}, }; struct rpc_clnt_program cli_prog = { diff --git a/cli/src/cli.h b/cli/src/cli.h index 4ef1dbe06f6..0a2fdb54b07 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -230,6 +230,10 @@ cli_cmd_log_locate_parse (const char **words, int wordcount, dict_t **options); int32_t cli_cmd_log_filename_parse (const char **words, int wordcount, dict_t **options); +int32_t +cli_cmd_volume_statedump_options_parse (const char **words, int wordcount, + dict_t **options); + cli_local_t * cli_local_get (); void diff --git a/libglusterfs/src/common-utils.c b/libglusterfs/src/common-utils.c index 6ee32cac747..b2e91608b7a 100644 --- a/libglusterfs/src/common-utils.c +++ b/libglusterfs/src/common-utils.c @@ -1877,4 +1877,22 @@ get_path_name (char *word, char **path) return *path; } +void +gf_path_strip_trailing_slashes (char *path) +{ + int i = 0; + int len = 0; + if (!path) + return; + + len = strlen (path); + for (i = len - 1; i > 0; i--) + if (path[i] != '/') + break; + + if (i < (len -1)) + path [i+1] = '\0'; + + return; +} diff --git a/libglusterfs/src/common-utils.h b/libglusterfs/src/common-utils.h index c7d784ca8f7..82e499b392a 100644 --- a/libglusterfs/src/common-utils.h +++ b/libglusterfs/src/common-utils.h @@ -133,6 +133,18 @@ extern char *gf_mgmt_list[GF_MGMT_MAXVALUE]; } \ } while (0); +#define GF_REMOVE_SLASH_FROM_PATH(path, string) \ + do { \ + int i = 0; \ + for (i = 1; i < strlen (path); i++) { \ + string[i-1] = path[i]; \ + if (string[i-1] == '/') \ + string[i-1] = '-'; \ + } \ + } while (0); \ + + + #define GF_FILE_CONTENT_REQUESTED(_xattr_req,_content_limit) \ (dict_get_uint64 (_xattr_req, "glusterfs.content", _content_limit) == 0) @@ -386,4 +398,5 @@ char *gf_uint64_2human_readable (uint64_t); int validate_brick_name (char *brick); char *get_host_name (char *word, char **host); char *get_path_name (char *word, char **path); +void gf_path_strip_trailing_slashes (char *path); #endif /* _COMMON_UTILS_H */ diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index 8247c60fbf6..57a542bb35a 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -352,6 +352,7 @@ struct _glusterfs_ctx { struct list_head mempool_list; /* used to keep a global list of mempools, used to log details of mempool in statedump */ + char *statedump_path; }; typedef struct _glusterfs_ctx glusterfs_ctx_t; diff --git a/libglusterfs/src/statedump.c b/libglusterfs/src/statedump.c index cf947996b6b..525980bfacd 100644 --- a/libglusterfs/src/statedump.c +++ b/libglusterfs/src/statedump.c @@ -23,6 +23,7 @@ #include "iobuf.h" #include "statedump.h" #include "stack.h" +#include "common-utils.h" #ifdef HAVE_MALLOC_H #include @@ -62,13 +63,13 @@ gf_proc_dump_unlock (void) static int -gf_proc_dump_open (void) +gf_proc_dump_open (char *dump_dir, char *brickname) { - char path[256]; + char path[PATH_MAX] = {0,}; int dump_fd = -1; - memset (path, 0, sizeof (path)); - snprintf (path, sizeof (path), "%s.%d", GF_DUMP_LOGFILE_ROOT, getpid ()); + snprintf (path, sizeof (path), "%s/%s.%d.dump", (dump_dir ? + dump_dir : "/tmp"), brickname, getpid()); dump_fd = open (path, O_CREAT|O_RDWR|O_TRUNC|O_APPEND, 0600); if (dump_fd < 0) @@ -355,6 +356,41 @@ gf_proc_dump_oldgraph_xlator_info (xlator_t *top) return; } +static int +gf_proc_dump_enable_all_options () +{ + + GF_PROC_DUMP_SET_OPTION (dump_options.dump_mem, _gf_true); + GF_PROC_DUMP_SET_OPTION (dump_options.dump_iobuf, _gf_true); + GF_PROC_DUMP_SET_OPTION (dump_options.dump_callpool, _gf_true); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_priv, _gf_true); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inode, _gf_true); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fd, _gf_true); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inodectx, + _gf_true); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fdctx, _gf_true); + + return 0; +} + +static int +gf_proc_dump_disable_all_options () +{ + + GF_PROC_DUMP_SET_OPTION (dump_options.dump_mem, _gf_false); + GF_PROC_DUMP_SET_OPTION (dump_options.dump_iobuf, _gf_false); + GF_PROC_DUMP_SET_OPTION (dump_options.dump_callpool, _gf_false); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_priv, _gf_false); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inode, + _gf_false); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fd, _gf_false); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inodectx, + _gf_false); + GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fdctx, _gf_false); + + return 0; +} + static int gf_proc_dump_parse_set_option (char *key, char *value) { @@ -363,7 +399,10 @@ gf_proc_dump_parse_set_option (char *key, char *value) char buf[GF_DUMP_MAX_BUF_LEN]; int ret = -1; - if (!strncasecmp (key, "mem", 3)) { + if (!strncasecmp (key, "all", 3)) { + (void)gf_proc_dump_enable_all_options (); + return 0; + } else if (!strncasecmp (key, "mem", 3)) { opt_key = &dump_options.dump_mem; } else if (!strncasecmp (key, "iobuf", 5)) { opt_key = &dump_options.dump_iobuf; @@ -398,44 +437,8 @@ gf_proc_dump_parse_set_option (char *key, char *value) return 0; } - static int -gf_proc_dump_enable_all_options () -{ - - GF_PROC_DUMP_SET_OPTION (dump_options.dump_mem, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_iobuf, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_callpool, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_priv, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inode, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fd, _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inodectx, - _gf_true); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fdctx, _gf_true); - - return 0; -} - -static int -gf_proc_dump_disable_all_options () -{ - - GF_PROC_DUMP_SET_OPTION (dump_options.dump_mem, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_iobuf, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.dump_callpool, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_priv, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inode, - _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fd, _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_inodectx, - _gf_false); - GF_PROC_DUMP_SET_OPTION (dump_options.xl_options.dump_fdctx, _gf_false); - - return 0; -} - -static int -gf_proc_dump_options_init () +gf_proc_dump_options_init (char *dump_name) { int ret = -1; FILE *fp = NULL; @@ -443,9 +446,12 @@ gf_proc_dump_options_init () char dumpbuf[GF_DUMP_MAX_BUF_LEN]; char *key = NULL, *value = NULL; char *saveptr = NULL; + char dump_option_file[PATH_MAX]; + snprintf (dump_option_file, sizeof (dump_option_file), + "/tmp/glusterdump.%d.options", getpid ()); - fp = fopen (GF_DUMP_OPTIONFILE, "r"); + fp = fopen (dump_option_file, "r"); if (!fp) { //ENOENT, return success @@ -489,19 +495,26 @@ gf_proc_dump_info (int signum) int ret = -1; glusterfs_ctx_t *ctx = NULL; glusterfs_graph_t *trav = NULL; + char brick_name[PATH_MAX] = {0,}; gf_proc_dump_lock (); - ret = gf_proc_dump_open (); - if (ret < 0) + + ctx = glusterfs_ctx_get (); + if (!ctx) goto out; - ret = gf_proc_dump_options_init (); + if (ctx->cmd_args.brick_name) { + GF_REMOVE_SLASH_FROM_PATH (ctx->cmd_args.brick_name, brick_name); + } else + strncpy (brick_name, "glusterdump", sizeof (brick_name)); + + ret = gf_proc_dump_options_init (brick_name); if (ret < 0) goto out; - ctx = glusterfs_ctx_get (); - if (!ctx) - goto close; + ret = gf_proc_dump_open (ctx->statedump_path, brick_name); + if (ret < 0) + goto out; if (GF_PROC_DUMP_IS_OPTION_ENABLED (mem)) { gf_proc_dump_mem_info (); @@ -534,7 +547,6 @@ gf_proc_dump_info (int signum) i++; } -close: gf_proc_dump_close (); out: gf_proc_dump_unlock (); diff --git a/libglusterfs/src/statedump.h b/libglusterfs/src/statedump.h index 43330b37c36..fb07f5927a2 100644 --- a/libglusterfs/src/statedump.h +++ b/libglusterfs/src/statedump.h @@ -26,11 +26,6 @@ #define GF_DUMP_MAX_BUF_LEN 4096 -#define GF_DUMP_LOGFILE_ROOT "/tmp/glusterdump" -#define GF_DUMP_LOGFILE_ROOT_LEN 256 - -#define GF_DUMP_OPTIONFILE "/tmp/glusterdump.input" - typedef struct gf_dump_xl_options_ { gf_boolean_t dump_priv; gf_boolean_t dump_inode; diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 41197044b66..b0918e43707 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -206,6 +206,7 @@ enum gluster_cli_procnum { GLUSTER_CLI_MOUNT, GLUSTER_CLI_UMOUNT, GLUSTER_CLI_HEAL_VOLUME, + GLUSTER_CLI_STATEDUMP_VOLUME, GLUSTER_CLI_MAXVALUE, }; diff --git a/rpc/xdr/src/cli1-xdr.c b/rpc/xdr/src/cli1-xdr.c index 7a1c6c91809..8e2adc51c88 100644 --- a/rpc/xdr/src/cli1-xdr.c +++ b/rpc/xdr/src/cli1-xdr.c @@ -1099,3 +1099,37 @@ xdr_gf1_cli_heal_vol_rsp (XDR *xdrs, gf1_cli_heal_vol_rsp *objp) return FALSE; return TRUE; } + +bool_t +xdr_gf1_cli_statedump_vol_req (XDR *xdrs, gf1_cli_statedump_vol_req *objp) +{ + register int32_t *buf; + buf = NULL; + + if (!xdr_string (xdrs, &objp->volname, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->options, ~0)) + return FALSE; + if (!xdr_int (xdrs, &objp->option_cnt)) + return FALSE; + return TRUE; +} + +bool_t +xdr_gf1_cli_statedump_vol_rsp (XDR *xdrs, gf1_cli_statedump_vol_rsp *objp) +{ + register int32_t *buf; + buf = NULL; + + if (!xdr_int (xdrs, &objp->op_ret)) + return FALSE; + if (!xdr_int (xdrs, &objp->op_errno)) + return FALSE; + if (!xdr_string (xdrs, &objp->volname, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->op_errstr, ~0)) + return FALSE; + if (!xdr_bytes (xdrs, (char **)&objp->dict.dict_val, (u_int *) &objp->dict.dict_len, ~0)) + return FALSE; + return TRUE; +} diff --git a/rpc/xdr/src/cli1-xdr.h b/rpc/xdr/src/cli1-xdr.h index 436bf986d47..56a5f4802ff 100644 --- a/rpc/xdr/src/cli1-xdr.h +++ b/rpc/xdr/src/cli1-xdr.h @@ -632,6 +632,25 @@ struct gf1_cli_heal_vol_rsp { }; typedef struct gf1_cli_heal_vol_rsp gf1_cli_heal_vol_rsp; +struct gf1_cli_statedump_vol_req { + char *volname; + char *options; + int option_cnt; +}; +typedef struct gf1_cli_statedump_vol_req gf1_cli_statedump_vol_req; + +struct gf1_cli_statedump_vol_rsp { + int op_ret; + int op_errno; + char *volname; + char *op_errstr; + struct { + u_int dict_len; + char *dict_val; + } dict; +}; +typedef struct gf1_cli_statedump_vol_rsp gf1_cli_statedump_vol_rsp; + /* the xdr functions */ #if defined(__STDC__) || defined(__cplusplus) @@ -707,6 +726,8 @@ extern bool_t xdr_gf1_cli_umount_req (XDR *, gf1_cli_umount_req*); extern bool_t xdr_gf1_cli_umount_rsp (XDR *, gf1_cli_umount_rsp*); extern bool_t xdr_gf1_cli_heal_vol_req (XDR *, gf1_cli_heal_vol_req*); extern bool_t xdr_gf1_cli_heal_vol_rsp (XDR *, gf1_cli_heal_vol_rsp*); +extern bool_t xdr_gf1_cli_statedump_vol_req (XDR *, gf1_cli_statedump_vol_req*); +extern bool_t xdr_gf1_cli_statedump_vol_rsp (XDR *, gf1_cli_statedump_vol_rsp*); #else /* K&R C */ extern bool_t xdr_gf_cli_defrag_type (); @@ -781,6 +802,8 @@ extern bool_t xdr_gf1_cli_umount_req (); extern bool_t xdr_gf1_cli_umount_rsp (); extern bool_t xdr_gf1_cli_heal_vol_req (); extern bool_t xdr_gf1_cli_heal_vol_rsp (); +extern bool_t xdr_gf1_cli_statedump_vol_req (); +extern bool_t xdr_gf1_cli_statedump_vol_rsp (); #endif /* K&R C */ diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x index 9a1f77c0ef7..5ff7aa3e98a 100644 --- a/rpc/xdr/src/cli1-xdr.x +++ b/rpc/xdr/src/cli1-xdr.x @@ -466,4 +466,17 @@ struct gf1_cli_heal_vol_rsp { string volname<>; string op_errstr<>; opaque dict<>; -} ; +}; +struct gf1_cli_statedump_vol_req { + string volname<>; + string options<>; + int option_cnt; +}; + +struct gf1_cli_statedump_vol_rsp { + int op_ret; + int op_errno; + string volname<>; + string op_errstr<>; + opaque dict<>; +}; diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 808459cfb7c..4e4b73bf493 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -2784,8 +2784,8 @@ rpcsvc_actor_t gd_svc_cli_actors[] = { [GLUSTER_CLI_STATUS_VOLUME] = {"STATUS_VOLUME", GLUSTER_CLI_STATUS_VOLUME, glusterd_handle_status_volume, NULL, NULL}, [GLUSTER_CLI_MOUNT] = { "MOUNT", GLUSTER_CLI_MOUNT, glusterd_handle_mount, NULL, NULL}, [GLUSTER_CLI_UMOUNT] = { "UMOUNT", GLUSTER_CLI_UMOUNT, glusterd_handle_umount, NULL, NULL}, - [GLUSTER_CLI_HEAL_VOLUME] = { "HEAL_VOLUME", GLUSTER_CLI_HEAL_VOLUME, glusterd_handle_cli_heal_volume, NULL, NULL} - + [GLUSTER_CLI_HEAL_VOLUME] = { "HEAL_VOLUME", GLUSTER_CLI_HEAL_VOLUME, glusterd_handle_cli_heal_volume, NULL, NULL}, + [GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", GLUSTER_CLI_STATEDUMP_VOLUME, glusterd_handle_cli_statedump_volume, NULL, NULL}, }; struct rpcsvc_program gd_svc_cli_prog = { diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c index 4271fe2460e..bb8cccfbfeb 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -1544,6 +1544,7 @@ glusterd_op_build_payload (dict_t **req) case GD_OP_STATUS_VOLUME: case GD_OP_REBALANCE: case GD_OP_HEAL_VOLUME: + case GD_OP_STATEDUMP_VOLUME: { dict_t *dict = ctx; dict_copy (dict, req_dict); @@ -2321,6 +2322,11 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_stage_heal_volume (dict, op_errstr); break; + case GD_OP_STATEDUMP_VOLUME: + ret = glusterd_op_stage_statedump_volume (dict, + op_errstr); + break; + default: gf_log ("", GF_LOG_ERROR, "Unknown op %d", op); @@ -2400,21 +2406,25 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_quota (dict, op_errstr); break; - case GD_OP_LOG_LEVEL: - ret = glusterd_op_log_level (dict); - break; + case GD_OP_LOG_LEVEL: + ret = glusterd_op_log_level (dict); + break; + + case GD_OP_STATUS_VOLUME: + ret = glusterd_op_status_volume (dict, op_errstr, rsp_dict); + break; - case GD_OP_STATUS_VOLUME: - ret = glusterd_op_status_volume (dict, op_errstr, rsp_dict); - break; + case GD_OP_REBALANCE: + ret = glusterd_op_rebalance (dict, op_errstr, rsp_dict); + break; - case GD_OP_REBALANCE: - ret = glusterd_op_rebalance (dict, op_errstr, rsp_dict); - break; + case GD_OP_HEAL_VOLUME: + ret = glusterd_op_heal_volume (dict, op_errstr); + break; - case GD_OP_HEAL_VOLUME: - ret = glusterd_op_heal_volume (dict, op_errstr); - break; + case GD_OP_STATEDUMP_VOLUME: + ret = glusterd_op_statedump_volume (dict); + break; default: gf_log ("", GF_LOG_ERROR, "Unknown op %d", @@ -3516,6 +3526,7 @@ glusterd_op_free_ctx (glusterd_op_t op, void *ctx) case GD_OP_STATUS_VOLUME: case GD_OP_REBALANCE: case GD_OP_HEAL_VOLUME: + case GD_OP_STATEDUMP_VOLUME: dict_unref (ctx); break; case GD_OP_DELETE_VOLUME: diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c index 4d7e687f2e9..615446a6251 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c @@ -470,6 +470,20 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret, break; } + case GD_OP_STATEDUMP_VOLUME: + { + gf1_cli_statedump_vol_rsp rsp = {0,}; + rsp.op_ret = op_ret; + rsp.op_errno = errno; + rsp.volname = ""; + if (op_errstr) + rsp.op_errstr = op_errstr; + else + rsp.op_errstr = ""; + cli_rsp = &rsp; + xdrproc = (xdrproc_t) xdr_gf1_cli_statedump_vol_rsp; + break; + } case GD_OP_NONE: case GD_OP_MAX: { diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 3681d4b9565..e27d2209f44 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -4161,3 +4161,112 @@ glusterd_is_volume_replicate (glusterd_volinfo_t *volinfo) replicates = _gf_true; return replicates; } + +int +glusterd_set_dump_options (char *dumpoptions_path, char *options, + int option_cnt) +{ + int ret = -1; + char *dup_options = NULL; + char *option = NULL; + char *tmpptr = NULL; + FILE *fp = NULL; + + if (0 == option_cnt) { + ret = 0; + goto out; + } + + fp = fopen (dumpoptions_path, "w"); + if (!fp) { + ret = -1; + goto out; + } + dup_options = gf_strdup (options); + gf_log ("", GF_LOG_INFO, "Recieved following statedump options: %s", + dup_options); + option = strtok_r (dup_options, " ", &tmpptr); + while (option) { + fprintf (fp, "%s=yes\n", option); + option = strtok_r (NULL, " ", &tmpptr); + } + +out: + if (fp) + fclose (fp); + return ret; +} + +int +glusterd_brick_statedump (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + char *options, int option_cnt) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char pidfile_path[PATH_MAX] = {0,}; + char path[PATH_MAX] = {0,}; + char dumpoptions_path[PATH_MAX] = {0,}; + FILE *pidfile = NULL; + pid_t pid = -1; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + if (uuid_is_null (brickinfo->uuid)) { + ret = glusterd_resolve_brick (brickinfo); + if (ret) { + gf_log ("glusterd", GF_LOG_ERROR, + "Cannot resolve brick %s:%s", + brickinfo->hostname, brickinfo->path); + goto out; + } + } + + if (uuid_compare (brickinfo->uuid, conf->uuid)) { + ret = 0; + goto out; + } + + GLUSTERD_GET_VOLUME_DIR (path, volinfo, conf); + GLUSTERD_GET_BRICK_PIDFILE (pidfile_path, path, brickinfo->hostname, + brickinfo->path); + + pidfile = fopen (pidfile_path, "r"); + if (!pidfile) { + gf_log ("", GF_LOG_ERROR, "Unable to open pidfile: %s", + pidfile_path); + ret = -1; + goto out; + } + + ret = fscanf (pidfile, "%d", &pid); + if (ret <= 0) { + gf_log ("", GF_LOG_ERROR, "Unable to get pid of brick process"); + ret = -1; + goto out; + } + + snprintf (dumpoptions_path, sizeof (dumpoptions_path), + "/tmp/glusterdump.%d.options", pid); + glusterd_set_dump_options (dumpoptions_path, options, option_cnt); + + + gf_log ("", GF_LOG_INFO, "Performing statedump on brick with pid %d", + pid); + + kill (pid, SIGUSR1); + + sleep (1); + unlink (dumpoptions_path); + + ret = 0; +out: + if (pidfile) + fclose (pidfile); + return ret; +} + diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index aca46eae120..3cc137e0579 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -352,6 +352,11 @@ glusterd_add_brick_to_dict (glusterd_volinfo_t *volinfo, gf_boolean_t glusterd_is_fuse_available (); +int +glusterd_brick_statedump (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + char *options, int option_cnt); + gf_boolean_t glusterd_is_volume_replicate (glusterd_volinfo_t *volinfo); gf_boolean_t diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index e1934493a6b..13c1bffa090 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -193,6 +193,7 @@ static struct volopt_map_entry glusterd_volopt_map[] = { {VKEY_FEATURES_QUOTA, "features/marker", "quota", "off", NO_DOC, OPT_FLAG_FORCE}, {VKEY_FEATURES_LIMIT_USAGE, "features/quota", "limit-set", NULL, NO_DOC, 0}, {"features.quota-timeout", "features/quota", "timeout", "0", DOC, 0}, + {"server.statedump-path", "protocol/server", "statedump-path", NULL, NO_DOC, 0}, {NULL, } }; diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c index 816ef9b184e..21e7973863a 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c @@ -447,6 +447,65 @@ out: return ret; } +int +glusterd_handle_cli_statedump_volume (rpcsvc_request_t *req) +{ + int32_t ret = -1; + gf1_cli_statedump_vol_req cli_req = {0,}; + char *dup_volname = NULL; + char *dup_options = NULL; + dict_t *dict = NULL; + + GF_ASSERT (req); + + ret = -1; + if (!xdr_to_generic (req->msg[0], &cli_req, + (xdrproc_t)xdr_gf1_cli_statedump_vol_req)) { + req->rpc_err = GARBAGE_ARGS; + goto out; + } + gf_log ("glusterd", GF_LOG_INFO, "Recieved statedump request for " + "volume %s with options %s", cli_req.volname, cli_req.options); + dict = dict_new (); + + if (!dict) + goto out; + + dup_volname = gf_strdup (cli_req.volname); + if (!dup_volname) + goto out; + ret = dict_set_dynstr (dict, "volname", dup_volname); + if (ret) + goto out; + + dup_options = gf_strdup(cli_req.options); + if (!dup_volname) + goto out; + ret = dict_set_dynstr (dict, "options", dup_options); + if (ret) + goto out; + + ret = dict_set_int32 (dict, "option_cnt", cli_req.option_cnt); + if (ret) + goto out; + + ret = glusterd_op_begin (req, GD_OP_STATEDUMP_VOLUME, dict); + + gf_cmd_log ("statedump", "on volume %s %s", cli_req.volname, + ((0 == ret) ? "SUCCEEDED" : "FAILED")); + +out: + if (ret && dict) + dict_unref (dict); + if (cli_req.volname) + free (cli_req.volname); + if (cli_req.options) + free (cli_req.options); + glusterd_friend_sm (); + glusterd_op_sm(); + + return ret; +} /* op-sm */ int @@ -609,6 +668,37 @@ out: return ret; } +int +glusterd_op_statedump_volume_args_get (dict_t *dict, char **volname, + char **options, int *option_cnt) +{ + int ret = -1; + + if (!dict || !volname || !options || !option_cnt) + goto out; + + ret = dict_get_str (dict, "volname", volname); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to get volname"); + goto out; + } + + ret = dict_get_str (dict, "options", options); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to get options"); + goto out; + } + + ret = dict_get_int32 (dict, "option_cnt", option_cnt); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to get option count"); + goto out; + } + +out: + return ret; +} + int glusterd_op_stage_start_volume (dict_t *dict, char **op_errstr) { @@ -904,6 +994,46 @@ out: return ret; } +int +glusterd_op_stage_statedump_volume (dict_t *dict, char **op_errstr) +{ + int ret = -1; + char *volname = NULL; + char *options = NULL; + int option_cnt = 0; + gf_boolean_t is_running = _gf_false; + glusterd_volinfo_t *volinfo = NULL; + char msg[2408] = {0,}; + + ret = glusterd_op_statedump_volume_args_get (dict, &volname, &options, + &option_cnt); + if (ret) + goto out; + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + snprintf (msg, sizeof(msg), "Volume %s does not exist", + volname); + gf_log ("", GF_LOG_ERROR, "%s", msg); + *op_errstr = gf_strdup (msg); + goto out; + } + + is_running = glusterd_is_volume_started (volinfo); + if (!is_running) { + snprintf (msg, sizeof(msg), "Volume %s is not in a started" + " state", volname); + gf_log ("", GF_LOG_ERROR, "%s", msg); + *op_errstr = gf_strdup (msg); + ret = -1; + goto out; + } + +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + int glusterd_op_create_volume (dict_t *dict, char **op_errstr) { @@ -1204,3 +1334,34 @@ glusterd_op_heal_volume (dict_t *dict, char **op_errstr) return ret; } + +int +glusterd_op_statedump_volume (dict_t *dict) +{ + int ret = 0; + char *volname = NULL; + char *options = NULL; + int option_cnt = 0; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + + ret = glusterd_op_statedump_volume_args_get (dict, &volname, &options, + &option_cnt); + if (ret) + goto out; + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) + goto out; + gf_log ("", GF_LOG_DEBUG, "Performing statedump on volume %s", volname); + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + ret = glusterd_brick_statedump (volinfo, brickinfo, options, + option_cnt); + if (ret) + goto out; + } + +out: + return ret; +} + diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index f5a10189b0e..203f6e975c7 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -80,6 +80,7 @@ typedef enum glusterd_op_ { GD_OP_STATUS_VOLUME, GD_OP_REBALANCE, GD_OP_HEAL_VOLUME, + GD_OP_STATEDUMP_VOLUME, GD_OP_MAX, } glusterd_op_t; @@ -541,17 +542,9 @@ glusterd_handle_log_level (rpcsvc_request_t *req); /* handler functions */ int32_t glusterd_op_begin (rpcsvc_request_t *req, glusterd_op_t op, void *ctx); -int glusterd_handle_gsync_set (rpcsvc_request_t *req); -int glusterd_handle_quota (rpcsvc_request_t *req); -int glusterd_handle_replace_brick (rpcsvc_request_t *req); -int glusterd_handle_log_filename (rpcsvc_request_t *req); -int glusterd_handle_log_locate (rpcsvc_request_t *req); -int glusterd_handle_log_level (rpcsvc_request_t *req); -int glusterd_handle_log_rotate (rpcsvc_request_t *req); -int glusterd_handle_create_volume (rpcsvc_request_t *req); -int glusterd_handle_cli_start_volume (rpcsvc_request_t *req); -int glusterd_handle_cli_stop_volume (rpcsvc_request_t *req); -int glusterd_handle_cli_delete_volume (rpcsvc_request_t *req); +/* removed other definitions as they have been defined elsewhere in this file*/ + +int glusterd_handle_cli_statedump_volume (rpcsvc_request_t *req); int glusterd_handle_defrag_start (glusterd_volinfo_t *volinfo, char *op_errstr, size_t len, int cmd, defrag_cbk_fn_t cbk); @@ -590,12 +583,15 @@ int glusterd_op_stage_remove_brick (dict_t *dict, char **op_errstr); int glusterd_op_stage_rebalance (dict_t *dict, char **op_errstr); int glusterd_op_rebalance (dict_t *dict, char **op_errstr, dict_t *rsp_dict); +int glusterd_op_stage_statedump_volume (dict_t *dict, char **op_errstr); +int glusterd_op_statedump_volume (dict_t *dict); /* misc */ void glusterd_do_replace_brick (void *data); int glusterd_op_perform_remove_brick (glusterd_volinfo_t *volinfo, char *brick, int force, int *need_migrate); int glusterd_op_stop_volume_args_get (dict_t *dict, char** volname, int *flags); - +int glusterd_op_statedump_volume_args_get (dict_t *dict, char **volname, + char **options, int *option_cnt); #endif diff --git a/xlators/protocol/server/src/server.c b/xlators/protocol/server/src/server.c index ec91ba7c21a..3b1f46ad397 100644 --- a/xlators/protocol/server/src/server.c +++ b/xlators/protocol/server/src/server.c @@ -508,7 +508,7 @@ reconfigure (xlator_t *this, dict_t *options) gf_boolean_t trace; data_t *data; int ret = 0; - + char *statedump_path = NULL; conf = this->private; if (!conf) { @@ -536,6 +536,27 @@ reconfigure (xlator_t *this, dict_t *options) " to %d", conf->trace); } + + /*ret = dict_get_str (options, "statedump-path", &statedump_path); + if (!ret) { + gf_path_strip_trailing_slashes (statedump_path); + if (this->ctx->statedump_path) + GF_FREE (this->ctx->statedump_path); + this->ctx->statedump_path = gf_strdup (statedump_path); + }*/ + GF_OPTION_RECONF ("statedump-path", statedump_path, + options, path, out); + if (!statedump_path) { + gf_log (this->name, GF_LOG_ERROR, + "Error while reconfiguring statedump path"); + ret = -1; + goto out; + } + gf_path_strip_trailing_slashes (statedump_path); + if (this->ctx->statedump_path) + GF_FREE (this->ctx->statedump_path); + this->ctx->statedump_path = gf_strdup (statedump_path); + if (!conf->auth_modules) conf->auth_modules = dict_new (); @@ -582,7 +603,7 @@ init (xlator_t *this) int32_t ret = -1; server_conf_t *conf = NULL; rpcsvc_listener_t *listener = NULL; - + char *statedump_path = NULL; GF_VALIDATE_OR_GOTO ("init", this, out); if (this->children == NULL) { @@ -614,6 +635,22 @@ init (xlator_t *this) if (ret) conf->conf_dir = CONFDIR; + /*ret = dict_get_str (this->options, "statedump-path", &statedump_path); + if (!ret) { + gf_path_strip_trailing_slashes (statedump_path); + this->ctx->statedump_path = statedump_path; + }*/ + GF_OPTION_INIT ("statedump-path", statedump_path, path, out); + if (statedump_path) { + gf_path_strip_trailing_slashes (statedump_path); + this->ctx->statedump_path = gf_strdup (statedump_path); + } else { + gf_log (this->name, GF_LOG_ERROR, + "Error setting statedump path"); + ret = -1; + goto out; + } + /* Authentication modules */ conf->auth_modules = dict_new (); GF_VALIDATE_OR_GOTO(this->name, conf->auth_modules, out); @@ -818,5 +855,9 @@ struct volume_options options[] = { { .key = {"rpc-auth-allow-insecure"}, .type = GF_OPTION_TYPE_BOOL, }, + { .key = {"statedump-path"}, + .type = GF_OPTION_TYPE_PATH, + .default_value = "/tmp" + }, { .key = {NULL} }, }; -- cgit