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 --- 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 ++++++- 9 files changed, 366 insertions(+), 28 deletions(-) (limited to 'xlators') diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 808459cfb..4e4b73bf4 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 4271fe246..bb8cccfbf 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 4d7e687f2..615446a62 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 3681d4b95..e27d2209f 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 aca46eae1..3cc137e05 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 e1934493a..13c1bffa0 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 816ef9b18..21e797386 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 f5a10189b..203f6e975 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 ec91ba7c2..3b1f46ad3 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