diff options
| author | Gaurav Kumar Garg <ggarg@redhat.com> | 2015-03-10 15:04:59 +0530 | 
|---|---|---|
| committer | Vijay Bellur <vbellur@redhat.com> | 2015-03-18 18:34:07 -0700 | 
| commit | d236b01a8bf68b83c76ea1cfa8351833e19695f7 (patch) | |
| tree | ee088fec3111b70dbf90c2af7fa7b43d6e97e019 | |
| parent | 7c4461329bba38b72536ee71a8172bc861ddf890 (diff) | |
cli/glusterd: cli command implementation for bitrot features
CLI command for bitrot features.
volume bitrot <volname> enable|disable
Above command will enable/disable bitrot feature for particular volume.
BUG: 1170075
Change-Id: Ie84002ef7f479a285688fdae99c7afa3e91b8b99
Signed-off-by: Gaurav Kumar Garg     <ggarg@redhat.com>
Signed-off-by: Anand nekkunti        <anekkunt@redhat.com>
Signed-off-by: Dominic P Geevarghese <dgeevarg@redhat.com>
Reviewed-on: http://review.gluster.org/9866
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vbellur@redhat.com>
| -rw-r--r-- | cli/src/cli-cmd-parser.c | 219 | ||||
| -rw-r--r-- | cli/src/cli-cmd-volume.c | 64 | ||||
| -rw-r--r-- | cli/src/cli-rpc-ops.c | 118 | ||||
| -rw-r--r-- | cli/src/cli.h | 3 | ||||
| -rw-r--r-- | rpc/rpc-lib/src/protocol-common.h | 1 | ||||
| -rw-r--r-- | rpc/xdr/src/cli1-xdr.x | 10 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/Makefile.am | 5 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-bitrot.c | 385 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-handler.c | 1 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-op-sm.c | 10 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-quota.c | 1 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 1 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.c | 6 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.h | 4 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volgen.h | 1 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-volume-set.c | 9 | ||||
| -rw-r--r-- | xlators/mgmt/glusterd/src/glusterd.h | 10 | 
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);  | 
