From d236b01a8bf68b83c76ea1cfa8351833e19695f7 Mon Sep 17 00:00:00 2001 From: Gaurav Kumar Garg Date: Tue, 10 Mar 2015 15:04:59 +0530 Subject: cli/glusterd: cli command implementation for bitrot features CLI command for bitrot features. volume bitrot enable|disable Above command will enable/disable bitrot feature for particular volume. BUG: 1170075 Change-Id: Ie84002ef7f479a285688fdae99c7afa3e91b8b99 Signed-off-by: Gaurav Kumar Garg Signed-off-by: Anand nekkunti Signed-off-by: Dominic P Geevarghese Reviewed-on: http://review.gluster.org/9866 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- cli/src/cli-cmd-parser.c | 219 ++++++++++++++ cli/src/cli-cmd-volume.c | 64 +++- cli/src/cli-rpc-ops.c | 118 ++++++++ cli/src/cli.h | 3 + rpc/rpc-lib/src/protocol-common.h | 1 + rpc/xdr/src/cli1-xdr.x | 10 + xlators/mgmt/glusterd/src/Makefile.am | 5 +- xlators/mgmt/glusterd/src/glusterd-bitrot.c | 385 ++++++++++++++++++++++++ xlators/mgmt/glusterd/src/glusterd-handler.c | 1 + xlators/mgmt/glusterd/src/glusterd-op-sm.c | 10 + xlators/mgmt/glusterd/src/glusterd-quota.c | 1 + xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 1 + xlators/mgmt/glusterd/src/glusterd-utils.c | 6 + xlators/mgmt/glusterd/src/glusterd-utils.h | 4 + xlators/mgmt/glusterd/src/glusterd-volgen.h | 1 + xlators/mgmt/glusterd/src/glusterd-volume-set.c | 9 + xlators/mgmt/glusterd/src/glusterd.h | 10 + 17 files changed, 845 insertions(+), 3 deletions(-) create mode 100644 xlators/mgmt/glusterd/src/glusterd-bitrot.c diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 83a9fbd7e7d..5520c9e46b1 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -4765,3 +4765,222 @@ out: return ret; } + +int +cli_cmd_validate_volume (char *volname) +{ + int i = 0; + int ret = -1; + + + if (volname[0] == '-') + return ret; + + if (!strcmp (volname, "all")) { + cli_err ("\"all\" cannot be the name of a volume."); + return ret; + } + + if (strchr (volname, '/')) { + cli_err ("Volume name should not contain \"/\" character."); + return ret; + } + + if (strlen (volname) > GD_VOLUME_NAME_MAX) { + cli_err ("Volname can not exceed %d characters.", + GD_VOLUME_NAME_MAX); + return ret; + } + + for (i = 0; i < strlen (volname); i++) + if (!isalnum (volname[i]) && (volname[i] != '_') && + (volname[i] != '-')) { + cli_err ("Volume name should not contain \"%c\"" + " character.\nVolume names can only" + "contain alphanumeric, '-' and '_' " + "characters.", volname[i]); + return ret; + } + + ret = 0; + + return ret; +} + +int32_t +cli_cmd_bitrot_parse (const char **words, int wordcount, dict_t **options) +{ + int32_t ret = -1; + char *w = NULL; + char *volname = NULL; + char *opwords[] = {"enable", "disable", + "scrub-throttle", + "scrub-frequency", + "scrub"}; + char *scrub_throt_values[] = {"frozen", "lazy", "normal", + "aggressive"}; + char *scrub_freq_values[] = {"daily", "weekly", + "biweekly", "monthly"}; + char *scrub_values[] = {"pause", "resume"}; + dict_t *dict = NULL; + gf_bitrot_type type = GF_BITROT_OPTION_TYPE_NONE; + + GF_ASSERT (words); + GF_ASSERT (options); + + dict = dict_new (); + if (!dict) + goto out; + + if (wordcount < 4 || wordcount > 5) { + gf_log ("", GF_LOG_ERROR, "Invalid syntax"); + goto out; + } + + volname = (char *)words[2]; + if (!volname) { + ret = -1; + goto out; + } + + ret = cli_cmd_validate_volume (volname); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to validate volume name"); + goto out; + } + + ret = dict_set_str (dict, "volname", volname); + if (ret) { + cli_out ("Failed to set volume name in dictionary "); + goto out; + } + + w = str_getunamb (words[3], opwords); + if (!w) { + cli_out ("Invalid bit rot option : %s", words[3]); + ret = -1; + goto out; + } + + if (strcmp (w, "enable") == 0) { + if (wordcount == 4) { + type = GF_BITROT_OPTION_TYPE_ENABLE; + ret = 0; + goto set_type; + } else { + ret = -1; + goto out; + } + } + + if (strcmp (w, "disable") == 0) { + if (wordcount == 4) { + type = GF_BITROT_OPTION_TYPE_DISABLE; + ret = 0; + goto set_type; + } else { + ret = -1; + goto out; + } + } + + if (!strcmp (w, "scrub-throttle")) { + if (!words[4]) { + cli_err ("Missing scrub-throttle value for bitrot " + "option"); + ret = -1; + goto out; + } else { + w = str_getunamb (words[4], scrub_throt_values); + if (!w) { + cli_err ("Invalid scrub-throttle option for " + "bitrot"); + ret = -1; + goto out; + } else { + type = GF_BITROT_OPTION_TYPE_SCRUB_THROTTLE; + ret = dict_set_str (dict, + "scrub-throttle-value", + (char *) words[4]); + if (ret) { + cli_out ("Failed to set scrub-throttle " + "value in the dict"); + goto out; + } + goto set_type; + } + } + } + + if (!strcmp (words[3], "scrub-frequency")) { + if (!words[4]) { + cli_err ("Missing scrub-frequency value"); + ret = -1; + goto out; + } else { + w = str_getunamb (words[4], scrub_freq_values); + if (!w) { + cli_err ("Invalid frequency option for bitrot"); + ret = -1; + goto out; + } else { + type = GF_BITROT_OPTION_TYPE_SCRUB_FREQ; + ret = dict_set_str (dict, + "scrub-frequency-value", + (char *) words[4]); + if (ret) { + cli_out ("Failed to set dict for " + "bitrot"); + goto out; + } + goto set_type; + } + } + } + + if (!strcmp (words[3], "scrub")) { + if (!words[4]) { + cli_err ("Missing scrub value for bitrot option"); + ret = -1; + goto out; + } else { + w = str_getunamb (words[4], scrub_values); + if (!w) { + cli_err ("Invalid scrub option for bitrot"); + ret = -1; + goto out; + } else { + type = GF_BITROT_OPTION_TYPE_SCRUB; + ret = dict_set_str (dict, "scrub-value", + (char *) words[4]); + if (ret) { + cli_out ("Failed to set dict for " + "bitrot"); + goto out; + } + goto set_type; + } + } + } else { + cli_err ("Invalid option %s for bitrot. Please enter valid " + "bitrot option", words[3]); + ret = -1; + goto out; + } + +set_type: + ret = dict_set_int32 (dict, "type", type); + if (ret < 0) + goto out; + + *options = dict; + +out: + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Unable to parse bitrot command"); + if (dict) + dict_destroy (dict); + } + + return ret; +} diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 5632a9798bb..6c950da4e97 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1299,6 +1299,58 @@ out: return ret; } +int +cli_cmd_bitrot_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + + int ret = -1; + int parse_err = 0; + call_frame_t *frame = NULL; + dict_t *options = NULL; + cli_local_t *local = NULL; + rpc_clnt_procedure_t *proc = NULL; + int sent = 0; + + ret = cli_cmd_bitrot_parse (words, wordcount, &options); + if (ret < 0) { + cli_usage_out (word->pattern); + parse_err = 1; + goto out; + } + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) { + ret = -1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_BITROT]; + if (proc == NULL) { + ret = -1; + goto out; + } + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_err == 0)) + cli_err ("Bit rot command failed. Please check the cli " + "logs for more details"); + + } + + CLI_STACK_DESTROY (frame); + + return ret; +} + int cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) @@ -2492,7 +2544,17 @@ struct cli_cmd volume_cmds[] = { }, {"volume get ", cli_cmd_volume_getopt_cbk, - "Get the value of the all options or given option for volume "}, + "Get the value of the all options or given option for volume " + }, + { "volume bitrot {enable|disable} |\n" + "volume bitrot {scrub-throttle frozen|lazy|normal" + "|aggressive} |\n" + "volume bitrot {scrub-frequency daily|weekly|biweekly" + "|monthly} |\n" + "volume bitrot {scrub pause|resume}", + cli_cmd_bitrot_cbk, + "Bitrot translator specific operations." + }, { NULL, NULL, NULL } }; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 928df1e7082..6e66e377ed5 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -9804,6 +9804,123 @@ out: } +int +gf_cli_bitrot_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + call_frame_t *frame = NULL; + + if (req->rpc_status == -1) { + ret = -1; + goto out; + } + + frame = myframe; + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + if (rsp.op_ret) { + ret = -1; + if (global_state->mode & GLUSTER_MODE_XML) + goto xml_output; + + if (strcmp (rsp.op_errstr, "")) + cli_err ("Bitrot command failed : %s", rsp.op_errstr); + else + cli_err ("Bitrot command : failed"); + + goto out; + } + + if (rsp.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "failed to unserialize " + "req-buffer to dictionary"); + goto out; + } + } + + gf_log ("cli", GF_LOG_DEBUG, "Received resp to bit rot command"); + +xml_output: + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_profile (dict, rsp.op_ret, + rsp.op_errno, + rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (!rsp.op_ret) + cli_out ("volume bitrot: success"); + + ret = rsp.op_ret; + +out: + if (dict) + dict_unref (dict); + + free (rsp.dict.dict_val); + free (rsp.op_errstr); + + cli_cmd_broadcast_response (ret); + + return ret; + +} + +int32_t +gf_cli_bitrot (call_frame_t *frame, xlator_t *this, void *data) +{ + gf_cli_req req = { {0,} }; + dict_t *options = NULL; + int ret = -1; + + if (!frame || !this || !data) + goto out; + + options = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_bitrot_cbk, + (xdrproc_t) xdr_gf_cli_req, options, + GLUSTER_CLI_BITROT, this, cli_rpc_prog, + NULL); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "cli_to_glusterd for " + "bitrot failed"); + goto out; + } + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + return ret; +} + struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_NULL] = {"NULL", NULL }, [GLUSTER_CLI_PROBE] = {"PROBE_QUERY", gf_cli_probe}, @@ -9848,6 +9965,7 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_BARRIER_VOLUME] = {"BARRIER VOLUME", gf_cli_barrier_volume}, [GLUSTER_CLI_GANESHA] = {"GANESHA", gf_cli_ganesha}, [GLUSTER_CLI_GET_VOL_OPT] = {"GET_VOL_OPT", gf_cli_get_vol_opt}, + [GLUSTER_CLI_BITROT] = {"BITROT", gf_cli_bitrot} }; struct rpc_clnt_program cli_prog = { diff --git a/cli/src/cli.h b/cli/src/cli.h index ad286ef5f85..ed2bc4aba8a 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -237,6 +237,9 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **opt); int32_t cli_cmd_quota_parse (const char **words, int wordcount, dict_t **opt); +int32_t +cli_cmd_bitrot_parse (const char **words, int wordcount, dict_t **opt); + int32_t cli_cmd_volume_set_parse (const char **words, int wordcount, dict_t **options, char **op_errstr); diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index b06b865bbb2..bf68366f5dd 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -182,6 +182,7 @@ enum gluster_cli_procnum { GLUSTER_CLI_BARRIER_VOLUME, GLUSTER_CLI_GET_VOL_OPT, GLUSTER_CLI_GANESHA, + GLUSTER_CLI_BITROT, GLUSTER_CLI_MAXVALUE, }; diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x index 3c9103545ac..925700699ab 100644 --- a/rpc/xdr/src/cli1-xdr.x +++ b/rpc/xdr/src/cli1-xdr.x @@ -37,6 +37,16 @@ GF_REPLACE_OP_COMMIT_FORCE }; +enum gf_bitrot_type { + GF_BITROT_OPTION_TYPE_NONE = 0, + GF_BITROT_OPTION_TYPE_ENABLE, + GF_BITROT_OPTION_TYPE_DISABLE, + GF_BITROT_OPTION_TYPE_SCRUB_THROTTLE, + GF_BITROT_OPTION_TYPE_SCRUB_FREQ, + GF_BITROT_OPTION_TYPE_SCRUB, + GF_BITROT_OPTION_TYPE_MAX +}; + enum gf1_op_commands { GF_OP_CMD_NONE = 0, GF_OP_CMD_START, diff --git a/xlators/mgmt/glusterd/src/Makefile.am b/xlators/mgmt/glusterd/src/Makefile.am index f95fc02d4fd..7792f12bae9 100644 --- a/xlators/mgmt/glusterd/src/Makefile.am +++ b/xlators/mgmt/glusterd/src/Makefile.am @@ -5,8 +5,9 @@ glusterd_la_LDFLAGS = -module -avoid-version glusterd_la_SOURCES = glusterd.c glusterd-handler.c glusterd-sm.c \ glusterd-op-sm.c glusterd-utils.c glusterd-rpc-ops.c \ glusterd-store.c glusterd-handshake.c glusterd-pmap.c \ - glusterd-volgen.c glusterd-rebalance.c glusterd-ganesha.c glusterd-quota.c \ - glusterd-geo-rep.c glusterd-replace-brick.c glusterd-log-ops.c \ + glusterd-volgen.c glusterd-rebalance.c glusterd-ganesha.c \ + glusterd-quota.c glusterd-bitrot.c glusterd-geo-rep.c \ + glusterd-replace-brick.c glusterd-log-ops.c \ glusterd-volume-ops.c glusterd-brick-ops.c glusterd-mountbroker.c \ glusterd-syncop.c glusterd-hooks.c glusterd-volume-set.c \ glusterd-locks.c glusterd-snapshot.c glusterd-mgmt-handler.c \ diff --git a/xlators/mgmt/glusterd/src/glusterd-bitrot.c b/xlators/mgmt/glusterd/src/glusterd-bitrot.c new file mode 100644 index 00000000000..44fefe82b7e --- /dev/null +++ b/xlators/mgmt/glusterd/src/glusterd-bitrot.c @@ -0,0 +1,385 @@ +/* + Copyright (c) 2011-2012 Red Hat, Inc. + 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. + */ + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "common-utils.h" +#include "cli1-xdr.h" +#include "xdr-generic.h" +#include "glusterd.h" +#include "glusterd-op-sm.h" +#include "glusterd-store.h" +#include "glusterd-utils.h" +#include "glusterd-volgen.h" +#include "run.h" +#include "syscall.h" +#include "byte-order.h" +#include "compat-errno.h" + +#include +#include + +const char *gd_bitrot_op_list[GF_BITROT_OPTION_TYPE_MAX] = { + [GF_BITROT_OPTION_TYPE_NONE] = "none", + [GF_BITROT_OPTION_TYPE_ENABLE] = "enable", + [GF_BITROT_OPTION_TYPE_DISABLE] = "disable", + [GF_BITROT_OPTION_TYPE_SCRUB_THROTTLE] = "scrub-throttle", + [GF_BITROT_OPTION_TYPE_SCRUB_FREQ] = "scrub-frequency", + [GF_BITROT_OPTION_TYPE_SCRUB] = "scrub", +}; + +int +__glusterd_handle_bitrot (rpcsvc_request_t *req) +{ + int32_t ret = -1; + gf_cli_req cli_req = { {0,} }; + dict_t *dict = NULL; + glusterd_op_t cli_op = GD_OP_BITROT; + char *volname = NULL; + int32_t type = 0; + char msg[2048] = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + + GF_ASSERT (req); + + this = THIS; + GF_ASSERT (this); + + conf = this->private; + GF_ASSERT (conf); + + ret = xdr_to_generic (req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req); + if (ret < 0) { + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + if (cli_req.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + ret = dict_unserialize (cli_req.dict.dict_val, + cli_req.dict.dict_len, + &dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "unserialize req-buffer to dictionary"); + snprintf (msg, sizeof (msg), "Unable to decode the " + "command"); + goto out; + } else { + dict->extra_stdfree = cli_req.dict.dict_val; + } + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + snprintf (msg, sizeof (msg), "Unable to get volume name"); + gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name, " + "while handling bitrot command"); + goto out; + } + + ret = dict_get_int32 (dict, "type", &type); + if (ret) { + snprintf (msg, sizeof (msg), "Unable to get type of command"); + gf_log (this->name, GF_LOG_ERROR, "Unable to get type of cmd, " + "while handling bitrot command"); + goto out; + } + + if (conf->op_version < GD_OP_VERSION_3_7_0) { + snprintf (msg, sizeof (msg), "Cannot execute command. The " + "cluster is operating at version %d. Bitrot command " + "%s is unavailable in this version", conf->op_version, + gd_bitrot_op_list[type]); + ret = -1; + goto out; + } + + ret = glusterd_op_begin_synctask (req, GD_OP_BITROT, dict); + +out: + if (ret) { + if (msg[0] == '\0') + snprintf (msg, sizeof (msg), "Bitrot operation failed"); + ret = glusterd_op_send_cli_response (cli_op, ret, 0, req, + dict, msg); + } + + return ret; +} + +int +glusterd_handle_bitrot (rpcsvc_request_t *req) +{ + return glusterd_big_locked_handler (req, __glusterd_handle_bitrot); +} + +static int +glusterd_bitrot_enable (glusterd_volinfo_t *volinfo, char **op_errstr) +{ + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + GF_VALIDATE_OR_GOTO (this->name, volinfo, out); + GF_VALIDATE_OR_GOTO (this->name, op_errstr, out); + + if (glusterd_is_volume_started (volinfo) == 0) { + *op_errstr = gf_strdup ("Volume is stopped, start volume " + "to enable bitrot."); + ret = -1; + goto out; + } + + ret = glusterd_is_bitrot_enabled (volinfo); + if (ret) { + *op_errstr = gf_strdup ("Bitrot is already enabled"); + ret = -1; + goto out; + } + + ret = dict_set_dynstr_with_alloc (volinfo->dict, VKEY_FEATURES_BITROT, + "on"); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "dict set failed"); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr && !*op_errstr) + gf_asprintf (op_errstr, "Enabling bitrot on volume %s has been " + "unsuccessful", volinfo->volname); + return ret; +} + +static int +glusterd_bitrot_disable (glusterd_volinfo_t *volinfo, char **op_errstr) +{ + int32_t ret = -1; + xlator_t *this = NULL; + + GF_VALIDATE_OR_GOTO (this->name, volinfo, out); + GF_VALIDATE_OR_GOTO (this->name, op_errstr, out); + + ret = dict_set_dynstr_with_alloc (volinfo->dict, VKEY_FEATURES_BITROT, + "off"); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "dict set failed"); + goto out; + } + + ret = 0; +out: + if (ret && op_errstr && !*op_errstr) + gf_asprintf (op_errstr, "Disabling bitrot on volume %s has " + "been unsuccessful", volinfo->volname); + return ret; +} + +static int +glusterd_manage_bitrot (int opcode) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + GF_ASSERT (priv); + + switch (opcode) { + case GF_BITROT_OPTION_TYPE_ENABLE: + /* TO DO: + * Start bitd service. once bitd volfile generation patch + * merge or this patch become dependent of bitd volfile + * generation patch below comment will remove. + * http://review.gluster.org/#/c/9710/ + */ + /*ret = priv->bitd_svc.manager (&(priv->bitd_svc), + NULL, PROC_START);*/ + case GF_BITROT_OPTION_TYPE_DISABLE: + + /* TO DO: + * Stop bitd service. once bitd volfile generation patch + * merge or this patch become dependent of bitd volfile + * generation patch below comment will remove. + * http://review.gluster.org/#/c/9710/ + */ + + /*if (glusterd_all_volumes_with_bitrot_stopped ()) + ret = glusterd_svc_stop (&(priv->bitd_svc), + SIGTERM); + */ + ret = 0; + break; + default: + ret = 0; + break; + } + + return ret; + +} + +int +glusterd_op_bitrot (dict_t *dict, char **op_errstr, dict_t *rsp_dict) +{ + glusterd_volinfo_t *volinfo = NULL; + int32_t ret = -1; + char *volname = NULL; + int type = -1; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + GF_ASSERT (dict); + GF_ASSERT (op_errstr); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_asprintf (op_errstr, FMTSTR_CHECK_VOL_EXISTS, volname); + goto out; + } + + ret = dict_get_int32 (dict, "type", &type); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to get type from " + "dict"); + goto out; + } + + switch (type) { + case GF_BITROT_OPTION_TYPE_ENABLE: + ret = glusterd_bitrot_enable (volinfo, op_errstr); + if (ret < 0) + goto out; + break; + + case GF_BITROT_OPTION_TYPE_DISABLE: + ret = glusterd_bitrot_disable (volinfo, op_errstr); + if (ret < 0) + goto out; + + break; + default: + gf_asprintf (op_errstr, "Bitrot command failed. Invalid " + "opcode"); + ret = -1; + goto out; + } + + ret = glusterd_manage_bitrot (type); + if (ret) + goto out; + + ret = glusterd_create_volfiles_and_notify_services (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to re-create " + "volfiles"); + ret = -1; + goto out; + } + + ret = glusterd_store_volinfo (volinfo, + GLUSTERD_VOLINFO_VER_AC_INCREMENT); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "Failed to store volinfo for " + "bitrot"); + goto out; + } + +out: + return ret; +} + +int +glusterd_op_stage_bitrot (dict_t *dict, char **op_errstr, dict_t *rsp_dict) +{ + int ret = 0; + char *volname = NULL; + int type = 0; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + GF_ASSERT (dict); + GF_ASSERT (op_errstr); + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to get volume name"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_asprintf (op_errstr, FMTSTR_CHECK_VOL_EXISTS, volname); + goto out; + } + + if (!glusterd_is_volume_started (volinfo)) { + *op_errstr = gf_strdup ("Volume is stopped, start volume " + "before executing bit rot command."); + ret = -1; + goto out; + } + + ret = dict_get_int32 (dict, "type", &type); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to get type for " + "operation"); + + *op_errstr = gf_strdup ("Staging stage failed for bitrot " + "operation."); + goto out; + } + + + if ((GF_BITROT_OPTION_TYPE_ENABLE != type) && + (glusterd_is_bitrot_enabled (volinfo) == 0)) { + ret = -1; + gf_asprintf (op_errstr, "Bitrot is not enabled on volume %s", + volname); + goto out; + } + + out: + if (ret && op_errstr && *op_errstr) + gf_log (this->name, GF_LOG_ERROR, "%s", *op_errstr); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 954fa859944..77fa96400ba 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -4841,6 +4841,7 @@ rpcsvc_actor_t gd_svc_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_BARRIER_VOLUME] = {"BARRIER_VOLUME", GLUSTER_CLI_BARRIER_VOLUME, glusterd_handle_barrier, NULL, 0, DRC_NA}, [GLUSTER_CLI_GANESHA] = { "GANESHA" , GLUSTER_CLI_GANESHA, glusterd_handle_ganesha_cmd, NULL, 0, DRC_NA}, [GLUSTER_CLI_GET_VOL_OPT] = {"GET_VOL_OPT", GLUSTER_CLI_GET_VOL_OPT, glusterd_handle_get_vol_opt, NULL, 0, DRC_NA}, + [GLUSTER_CLI_BITROT] = {"BITROT", GLUSTER_CLI_BITROT, glusterd_handle_bitrot, NULL, 0, DRC_NA}, }; 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 035b4528e10..75756518f28 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -3441,6 +3441,7 @@ glusterd_op_build_payload (dict_t **req, char **op_errstr, dict_t *op_ctx) case GD_OP_CLEARLOCKS_VOLUME: case GD_OP_DEFRAG_BRICK_VOLUME: case GD_OP_BARRIER: + case GD_OP_BITROT: { ret = dict_get_str (dict, "volname", &volname); if (ret) { @@ -4927,6 +4928,11 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_stage_barrier (dict, op_errstr); break; + case GD_OP_BITROT: + ret = glusterd_op_stage_bitrot (dict, op_errstr, + rsp_dict); + break; + default: gf_log (this->name, GF_LOG_ERROR, "Unknown op %s", gd_op_list[op]); @@ -5045,6 +5051,10 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_barrier (dict, op_errstr); break; + case GD_OP_BITROT: + ret = glusterd_op_bitrot (dict, op_errstr, rsp_dict); + break; + default: gf_log (this->name, GF_LOG_ERROR, "Unknown op %s", gd_op_list[op]); diff --git a/xlators/mgmt/glusterd/src/glusterd-quota.c b/xlators/mgmt/glusterd/src/glusterd-quota.c index f2a73057414..9179bf63ba9 100644 --- a/xlators/mgmt/glusterd/src/glusterd-quota.c +++ b/xlators/mgmt/glusterd/src/glusterd-quota.c @@ -1358,6 +1358,7 @@ out: } return ret; } + int glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict) { diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c index 353c757ba92..655f4b07f56 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c @@ -142,6 +142,7 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret, case GD_OP_QUOTA: case GD_OP_SNAP: case GD_OP_BARRIER: + case GD_OP_BITROT: { /*nothing specific to be done*/ break; diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 1cd9a7c4741..727a19d24d1 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -9158,6 +9158,12 @@ glusterd_is_volume_quota_enabled (glusterd_volinfo_t *volinfo) return (glusterd_volinfo_get_boolean (volinfo, VKEY_FEATURES_QUOTA)); } +int +glusterd_is_bitrot_enabled (glusterd_volinfo_t *volinfo) +{ + return glusterd_volinfo_get_boolean (volinfo, VKEY_FEATURES_BITROT); +} + int glusterd_validate_and_set_gfid (dict_t *op_ctx, dict_t *req_dict, char **op_errstr) diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index 4cfb51a9904..1956029192a 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -448,6 +448,7 @@ glusterd_volume_heal_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict); int32_t glusterd_check_if_quota_trans_enabled (glusterd_volinfo_t *volinfo); + int glusterd_volume_quota_copy_to_op_ctx_dict (dict_t *aggr, dict_t *rsp); int @@ -555,6 +556,9 @@ gd_should_i_start_rebalance (glusterd_volinfo_t *volinfo); int glusterd_is_volume_quota_enabled (glusterd_volinfo_t *volinfo); +int +glusterd_is_bitrot_enabled (glusterd_volinfo_t *volinfo); + gf_boolean_t glusterd_all_volumes_with_quota_stopped (); diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h index 0d742aae056..9b6c8c20146 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.h +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h @@ -33,6 +33,7 @@ #define VKEY_CHANGELOG "changelog.changelog" #define VKEY_FEATURES_QUOTA "features.quota" #define VKEY_FEATURES_TRASH "features.trash" +#define VKEY_FEATURES_BITROT "features.bitrot" #define AUTH_ALLOW_MAP_KEY "auth.allow" #define AUTH_REJECT_MAP_KEY "auth.reject" diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-set.c b/xlators/mgmt/glusterd/src/glusterd-volume-set.c index 385e9075ce7..cae7c07ed53 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-set.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-set.c @@ -1265,6 +1265,15 @@ struct volopt_map_entry glusterd_volopt_map[] = { .op_version = 1 }, + { .key = VKEY_FEATURES_BITROT, + .voltype = "features/bitrot", + .option = "bitrot", + .value = "off", + .type = NO_DOC, + .flags = OPT_FLAG_FORCE, + .op_version = GD_OP_VERSION_3_7_0 + }, + /* Debug xlators options */ { .key = "debug.trace", .voltype = "debug/trace", diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 7bc949c8cef..f70a4c85822 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -111,6 +111,7 @@ typedef enum glusterd_op_ { GD_OP_SNAP, GD_OP_BARRIER, GD_OP_GANESHA, + GD_OP_BITROT, GD_OP_MAX, } glusterd_op_t; @@ -848,6 +849,9 @@ glusterd_handle_gsync_set (rpcsvc_request_t *req); int glusterd_handle_quota (rpcsvc_request_t *req); +int +glusterd_handle_bitrot (rpcsvc_request_t *req); + int glusterd_handle_fsm_log (rpcsvc_request_t *req); @@ -935,7 +939,13 @@ int glusterd_op_sys_exec (dict_t *dict, char **op_errstr, dict_t *rsp_dict); int glusterd_op_stage_gsync_create (dict_t *dict, char **op_errstr); int glusterd_op_gsync_create (dict_t *dict, char **op_errstr, dict_t *rsp_dict); int glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict); + +int glusterd_op_bitrot (dict_t *dict, char **op_errstr, dict_t *rsp_dict); + int glusterd_op_stage_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict); + +int glusterd_op_stage_bitrot (dict_t *dict, char **op_errstr, dict_t *rsp_dict); + int glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr, dict_t *rsp_dict); int glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict); -- cgit