summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cli/src/cli-cmd-parser.c219
-rw-r--r--cli/src/cli-cmd-volume.c64
-rw-r--r--cli/src/cli-rpc-ops.c118
-rw-r--r--cli/src/cli.h3
-rw-r--r--rpc/rpc-lib/src/protocol-common.h1
-rw-r--r--rpc/xdr/src/cli1-xdr.x10
-rw-r--r--xlators/mgmt/glusterd/src/Makefile.am5
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-bitrot.c385
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-handler.c1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-op-sm.c10
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-quota.c1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-rpc-ops.c1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c6
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.h4
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.h1
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volume-set.c9
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.h10
17 files changed, 845 insertions, 3 deletions
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
@@ -1300,6 +1300,58 @@ out:
}
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 <VOLNAME> <key|all>",
cli_cmd_volume_getopt_cbk,
- "Get the value of the all options or given option for volume <VOLNAME>"},
+ "Get the value of the all options or given option for volume <VOLNAME>"
+ },
+ { "volume bitrot <volname> {enable|disable} |\n"
+ "volume bitrot <volname> {scrub-throttle frozen|lazy|normal"
+ "|aggressive} |\n"
+ "volume bitrot <volname> {scrub-frequency daily|weekly|biweekly"
+ "|monthly} |\n"
+ "volume bitrot <volname> {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
@@ -238,6 +238,9 @@ 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);
int32_t
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. <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.
+ */
+
+#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 <sys/wait.h>
+#include <dlfcn.h>
+
+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
@@ -9159,6 +9159,12 @@ glusterd_is_volume_quota_enabled (glusterd_volinfo_t *volinfo)
}
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;
@@ -849,6 +850,9 @@ 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);
int
@@ -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);