From 936f8aeac3252951e7fa0cdaa5d260fad3bd5ea0 Mon Sep 17 00:00:00 2001 From: Anuradha Talur Date: Mon, 22 Aug 2016 13:22:03 -0400 Subject: glusterd : Introduce reset brick The command basically allows replace brick with src and dst bricks as same. Usage: gluster v reset-brick start This command kills the brick to be reset. Once this command is run, admin can do other manual operations that they need to do, like configuring some options for the brick. Once this is done, resetting the brick can be continued with the following options. gluster v reset-brick commit {force} Does the job of resetting the brick. 'force' option should be used when the brick already contains volinfo id. Problem: On doing a disk-replacement of a brick in a replicate volume the following 2 scenarios may occur : a) there is a chance that reads are served from this replaced-disk brick, which leads to empty reads. b) potential data loss if next writes succeed only on replaced brick, and heal is done to other bricks from this one. Solution: After disk-replacement, make sure that reset-brick command is run for that brick so that pending markers are set for the brick and it is not chosen as source for reads and heal. But, as of now replace-brick for the same brick-path is not allowed. In order to fix the above mentioned problem, same brick-path replace-brick is needed. With this patch reset-brick commit {force} will be allowed even when source and destination are identical as long as 1) destination brick is not alive 2) source and destination brick have the same brick uuid and path. Also, the destination brick after replace-brick will use the same port as the source brick. Change-Id: I440b9e892ffb781ea4b8563688c3f85c7a7c89de BUG: 1266876 Signed-off-by: Anuradha Talur Reviewed-on: http://review.gluster.org/12250 Smoke: Gluster Build System NetBSD-regression: NetBSD Build System CentOS-regression: Gluster Build System Reviewed-by: Ashish Pandey Reviewed-by: Pranith Kumar Karampuri --- cli/src/cli-cmd-parser.c | 164 ++++++-- cli/src/cli-cmd-volume.c | 61 +++ cli/src/cli-rpc-ops.c | 223 ++++++++++- cli/src/cli-xml-output.c | 2 +- cli/src/cli.h | 7 +- events/eventskeygen.py | 2 + heal/src/glfs-heal.c | 2 +- rpc/rpc-lib/src/protocol-common.h | 1 + .../bug-1266876-allow-reset-brick-for-same-path.t | 54 +++ xlators/cluster/afr/src/afr-inode-write.c | 4 +- xlators/mgmt/glusterd/src/Makefile.am | 3 +- xlators/mgmt/glusterd/src/glusterd-brick-ops.c | 2 +- xlators/mgmt/glusterd/src/glusterd-handler.c | 1 + xlators/mgmt/glusterd/src/glusterd-hooks.c | 1 + xlators/mgmt/glusterd/src/glusterd-messages.h | 29 +- xlators/mgmt/glusterd/src/glusterd-mgmt.c | 33 ++ xlators/mgmt/glusterd/src/glusterd-mgmt.h | 6 + xlators/mgmt/glusterd/src/glusterd-op-sm.c | 1 + xlators/mgmt/glusterd/src/glusterd-replace-brick.c | 349 +++++------------ xlators/mgmt/glusterd/src/glusterd-reset-brick.c | 430 +++++++++++++++++++++ xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 1 + xlators/mgmt/glusterd/src/glusterd-syncop.c | 1 + xlators/mgmt/glusterd/src/glusterd-utils.c | 327 +++++++++++++++- xlators/mgmt/glusterd/src/glusterd-utils.h | 34 +- xlators/mgmt/glusterd/src/glusterd-volume-ops.c | 2 +- xlators/mgmt/glusterd/src/glusterd.c | 1 + xlators/mgmt/glusterd/src/glusterd.h | 6 + 27 files changed, 1431 insertions(+), 316 deletions(-) create mode 100644 tests/bugs/replicate/bug-1266876-allow-reset-brick-for-same-path.t create mode 100644 xlators/mgmt/glusterd/src/glusterd-reset-brick.c diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index be0a8e756d5..86b02877159 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -2134,6 +2134,137 @@ out: return ret; } +int32_t +cli_cmd_brick_op_validate_bricks (const char **words, dict_t *dict, + int src, int dst) +{ + int ret = -1; + char *delimiter = NULL; + + if (validate_brick_name ((char *)words[src])) { + cli_err ("wrong brick type: %s, use " + ":", words[3]); + ret = -1; + goto out; + } else { + delimiter = strrchr ((char *)words[src], '/'); + ret = gf_canonicalize_path (delimiter); + if (ret) + goto out; + } + + ret = dict_set_str (dict, "src-brick", (char *)words[src]); + if (ret) + goto out; + + if (dst == -1) { + ret = 0; + goto out; + } + + if (validate_brick_name ((char *)words[dst])) { + cli_err ("wrong brick type: %s, use " + ":", words[dst]); + ret = -1; + goto out; + } else { + delimiter = strrchr ((char *)words[dst], '/'); + ret = gf_canonicalize_path (delimiter); + if (ret) + goto out; + } + + ret = dict_set_str (dict, "dst-brick", (char *)words[dst]); + if (ret) + goto out; + ret = 0; +out: + return ret; +} + +int32_t +cli_cmd_volume_reset_brick_parse (const char **words, int wordcount, + dict_t **options) +{ + int ret = -1; + char *volname = NULL; + dict_t *dict = NULL; + + if (wordcount < 5 || wordcount > 7) + goto out; + + dict = dict_new (); + + if (!dict) + goto out; + + volname = (char *)words[2]; + + ret = dict_set_str (dict, "volname", volname); + if (ret) + goto out; + + if (wordcount == 5) { + if (strcmp (words[4], "start")) { + cli_err ("Invalid option '%s' for reset-brick. Please " + "enter valid reset-brick command", words[4]); + ret = -1; + goto out; + } + + ret = cli_cmd_brick_op_validate_bricks (words, dict, 3, -1); + if (ret) + goto out; + + ret = dict_set_str (dict, "operation", "GF_RESET_OP_START"); + if (ret) + goto out; + } else if (wordcount == 6) { + if (strcmp (words[5], "commit")) { + cli_err ("Invalid option '%s' for reset-brick. Please " + "enter valid reset-brick command", words[5]); + ret = -1; + goto out; + } + + ret = cli_cmd_brick_op_validate_bricks (words, dict, 3, 4); + if (ret) + goto out; + + ret = dict_set_str (dict, "operation", "GF_RESET_OP_COMMIT"); + if (ret) + goto out; + } else if (wordcount == 7) { + if (strcmp (words[5], "commit") || strcmp (words[6], "force")) { + cli_err ("Invalid option '%s %s' for reset-brick. Please " + "enter valid reset-brick command", + words[5], words[6]); + ret = -1; + goto out; + } + + ret = cli_cmd_brick_op_validate_bricks (words, dict, 3, 4); + if (ret) + goto out; + + ret = dict_set_str (dict, "operation", + "GF_RESET_OP_COMMIT_FORCE"); + if (ret) + goto out; + } + + *options = dict; + +out: + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Unable to parse reset-brick CLI"); + if (dict) + dict_unref (dict); + } + + return ret; +} int32_t cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, @@ -2141,7 +2272,6 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, { int ret = -1; char *volname = NULL; - char *delimiter = NULL; dict_t *dict = NULL; GF_ASSERT (words); @@ -2167,35 +2297,7 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, if (ret) goto out; - if (validate_brick_name ((char *)words[3])) { - cli_err ("wrong brick type: %s, use " - ":", words[3]); - ret = -1; - goto out; - } else { - delimiter = strrchr ((char *)words[3], ':'); - ret = gf_canonicalize_path (delimiter + 1); - if (ret) - goto out; - } - - ret = dict_set_str (dict, "src-brick", (char *)words[3]); - if (ret) - goto out; - - if (validate_brick_name ((char *)words[4])) { - cli_err ("wrong brick type: %s, use " - ":", words[4]); - ret = -1; - goto out; - } else { - delimiter = strrchr ((char *)words[4], ':'); - ret = gf_canonicalize_path (delimiter + 1); - if (ret) - goto out; - } - - ret = dict_set_str (dict, "dst-brick", (char *)words[4]); + ret = cli_cmd_brick_op_validate_bricks (words, dict, 3, 4); if (ret) goto out; @@ -2216,7 +2318,7 @@ cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, out: if (ret) { - gf_log ("cli", GF_LOG_ERROR, "Unable to parse replace-brick CLI"); + gf_log ("cli", GF_LOG_ERROR, "Unable to parse reset-brick CLI"); if (dict) dict_unref (dict); } diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index 020697ff56b..2171d357aa5 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1828,6 +1828,59 @@ out: } +int +cli_cmd_volume_reset_brick_cbk (struct cli_state *state, + struct cli_cmd_word *word, + const char **words, + int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *options = NULL; + int sent = 0; + int parse_error = 0; + cli_local_t *local = NULL; + +#ifdef GF_SOLARIS_HOST_OS + cli_out ("Command not supported on Solaris"); + goto out; +#endif + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_RESET_BRICK]; + + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + + ret = cli_cmd_volume_reset_brick_parse (words, wordcount, &options); + + if (ret) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + CLI_LOCAL_INIT (local, words, frame, options); + + if (proc->fn) { + ret = proc->fn (frame, THIS, options); + } + +out: + if (ret) { + gf_event (EVENT_BRICK_RESET, "Volume reset-brick failed."); + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("Volume reset-brick failed"); + } else { + gf_event (EVENT_BRICK_RESET, "Volume reset-brick succeeded."); + } + + CLI_STACK_DESTROY (frame); + + return ret; +} + int cli_cmd_volume_replace_brick_cbk (struct cli_state *state, struct cli_cmd_word *word, @@ -1868,9 +1921,12 @@ cli_cmd_volume_replace_brick_cbk (struct cli_state *state, out: if (ret) { + gf_event (EVENT_BRICK_REPLACE, "Volume replace-brick failed."); cli_cmd_sent_status_get (&sent); if ((sent == 0) && (parse_error == 0)) cli_out ("Volume replace-brick failed"); + } else { + gf_event (EVENT_BRICK_RESET, "Volume replace-brick succeeded."); } CLI_STACK_DESTROY (frame); @@ -3016,6 +3072,11 @@ struct cli_cmd volume_cmds[] = { "Bitrot translator specific operation. For more information about " "bitrot command type 'man gluster'" }, + { "volume reset-brick {{start} |" + " { commit}}", + cli_cmd_volume_reset_brick_cbk, + "reset-brick operations"}, + { NULL, NULL, NULL } }; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 6259546b6e9..6b5277ced95 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -2960,6 +2960,149 @@ out: return ret; } +int +gf_cli_reset_brick_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + char *src_brick = NULL; + char *dst_brick = NULL; + char *status_reply = NULL; + char *rb_operation_str = NULL; + dict_t *rsp_dict = NULL; + char msg[1024] = {0,}; + char *task_id_str = NULL; + char *reset_op = NULL; + + GF_ASSERT (myframe); + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + + GF_ASSERT (frame->local); + + local = frame->local; + + 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; + } + + ret = dict_get_str (local->dict, "operation", &reset_op); + if (ret) { + gf_log (frame->this->name, GF_LOG_ERROR, + "dict_get on operation failed"); + goto out; + } + + if (rsp.dict.dict_len) { + /* Unserialize the dictionary */ + rsp_dict = dict_new (); + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &rsp_dict); + if (ret < 0) { + gf_log (frame->this->name, GF_LOG_ERROR, "failed to " + "unserialize rsp buffer to dictionary"); + goto out; + } + } + + if (strcmp (reset_op, "GF_RESET_OP_START") && + strcmp (reset_op, "GF_RESET_OP_COMMIT") && + strcmp (reset_op, "GF_RESET_OP_COMMIT_FORCE")) { + rb_operation_str = gf_strdup ("Unknown operation"); + ret = -1; + goto out; + } + + if (rsp.op_ret && (strcmp (rsp.op_errstr, ""))) { + rb_operation_str = gf_strdup (rsp.op_errstr); + } else { + if (!strcmp (reset_op, "GF_RESET_OP_START")) { + if (rsp.op_ret) + rb_operation_str = gf_strdup ("reset-brick " + "start " + "operation " + "failed"); + else + rb_operation_str = gf_strdup ("reset-brick " + "start " + "operation " + "successful"); + } else if (!strcmp (reset_op, "GF_RESET_OP_COMMIT")) { + + if (rsp.op_ret) + rb_operation_str = gf_strdup ("reset-brick " + "commit " + "operation " + "failed"); + else + rb_operation_str = gf_strdup ("reset-brick " + "commit " + "operation " + "successful"); + } else if (!strcmp (reset_op, "GF_RESET_OP_COMMIT_FORCE")) { + + if (rsp.op_ret) + rb_operation_str = gf_strdup ("reset-brick " + "commit " + "force operation " + "failed"); + else + rb_operation_str = gf_strdup ("reset-brick " + "commit " + "force operation " + "successful"); + } + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to reset brick"); + snprintf (msg, sizeof (msg), "%s", + rb_operation_str ? rb_operation_str : "Unknown operation"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_replace_brick (rsp_dict, + rsp.op_ret, + rsp.op_errno, msg); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) + cli_err ("volume reset-brick: failed: %s", msg); + else + cli_out ("volume reset-brick: success: %s", msg); + ret = rsp.op_ret; + +out: + if (frame) + frame->local = NULL; + + if (local) + cli_local_wipe (local); + + if (rb_operation_str) + GF_FREE (rb_operation_str); + + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + if (rsp_dict) + dict_unref (rsp_dict); + + return ret; +} int gf_cli_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) @@ -2971,7 +3114,7 @@ gf_cli_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, char *rb_operation_str = NULL; dict_t *rsp_dict = NULL; char msg[1024] = {0,}; - char *replace_op = 0; + char *replace_op = NULL; GF_ASSERT (myframe); @@ -3013,7 +3156,7 @@ gf_cli_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, } } - if (!strcmp(replace_op, "GF_REPLACE_OP_COMMIT_FORCE")) { + if (!strcmp (replace_op, "GF_REPLACE_OP_COMMIT_FORCE")) { if (rsp.op_ret || ret) rb_operation_str = gf_strdup ("replace-brick commit " @@ -3035,7 +3178,7 @@ gf_cli_replace_brick_cbk (struct rpc_req *req, struct iovec *iov, rb_operation_str ? rb_operation_str : "Unknown operation"); if (global_state->mode & GLUSTER_MODE_XML) { - ret = cli_xml_output_vol_replace_brick (replace_op, rsp_dict, + ret = cli_xml_output_vol_replace_brick (rsp_dict, rsp.op_ret, rsp.op_errno, msg); if (ret) @@ -3054,10 +3197,8 @@ out: if (frame) frame->local = NULL; - if (local) { - dict_unref (local->dict); + if (local) cli_local_wipe (local); - } if (rb_operation_str) GF_FREE (rb_operation_str); @@ -4888,9 +5029,74 @@ out: return ret; } +int32_t +gf_cli_reset_brick (call_frame_t *frame, xlator_t *this, void *data) +{ + gf_cli_req req = { {0,} }; + int ret = 0; + dict_t *dict = NULL; + char *dst_brick = NULL; + char *src_brick = NULL; + char *volname = NULL; + char *op = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "operation", &op); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on operation failed"); + goto out; + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on volname failed"); + goto out; + } + + ret = dict_get_str (dict, "src-brick", &src_brick); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on src-brick failed"); + goto out; + } + + if (!strcmp (op, "GF_RESET_OP_COMMIT") || + !strcmp (op, "GF_RESET_OP_COMMIT_FORCE")) { + ret = dict_get_str (dict, "dst-brick", &dst_brick); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "dict_get on dst-brick failed"); + goto out; + } + } + + gf_log (this->name, GF_LOG_DEBUG, + "Received command reset-brick %s on %s.", op, src_brick); + + ret = cli_to_glusterd (&req, frame, gf_cli_reset_brick_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_RESET_BRICK, this, cli_rpc_prog, + NULL); + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + return ret; +} + int32_t gf_cli_replace_brick (call_frame_t *frame, xlator_t *this, - void *data) + void *data) { gf_cli_req req = {{0,}}; int ret = 0; @@ -11345,7 +11551,8 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_ATTACH_TIER] = {"ATTACH_TIER", gf_cli_attach_tier}, [GLUSTER_CLI_DETACH_TIER] = {"DETACH_TIER", gf_cli_detach_tier}, [GLUSTER_CLI_TIER] = {"TIER", gf_cli_tier}, - [GLUSTER_CLI_GET_STATE] = {"GET_STATE", gf_cli_get_state} + [GLUSTER_CLI_GET_STATE] = {"GET_STATE", gf_cli_get_state}, + [GLUSTER_CLI_RESET_BRICK] = {"RESET_BRICK", gf_cli_reset_brick} }; struct rpc_clnt_program cli_prog = { diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c index f2b1941b77b..6639262066c 100644 --- a/cli/src/cli-xml-output.c +++ b/cli/src/cli-xml-output.c @@ -3861,7 +3861,7 @@ out: } int -cli_xml_output_vol_replace_brick (char *op, dict_t *dict, +cli_xml_output_vol_replace_brick (dict_t *dict, int op_ret, int op_errno, char *op_errstr) { #if (HAVE_LIB_XML) diff --git a/cli/src/cli.h b/cli/src/cli.h index f9c642ee4d0..ba0d845381a 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -283,6 +283,10 @@ int32_t cli_cmd_volume_replace_brick_parse (const char **words, int wordcount, dict_t **options); +int32_t +cli_cmd_volume_reset_brick_parse (const char **words, int wordcount, + dict_t **options); + int32_t cli_cmd_log_rotate_parse (const char **words, int wordcount, dict_t **options); int32_t @@ -424,7 +428,7 @@ cli_xml_output_vol_remove_brick_detach_tier (gf_boolean_t status_op, const char *op); int -cli_xml_output_vol_replace_brick (char *op, dict_t *dict, int op_ret, +cli_xml_output_vol_replace_brick (dict_t *dict, int op_ret, int op_errno, char *op_errstr); int @@ -489,5 +493,4 @@ print_quota_list_empty (char *path, int type); int gf_gsync_status_t_comparator (const void *p, const void *q); - #endif /* __CLI_H__ */ diff --git a/events/eventskeygen.py b/events/eventskeygen.py index b55c29ae5a6..30b518dc18a 100644 --- a/events/eventskeygen.py +++ b/events/eventskeygen.py @@ -91,6 +91,8 @@ keys = ( "EVENT_QUOTA_HARD_TIMEOUT", "EVENT_QUOTA_DEFAULT_SOFT_LIMIT", "EVENT_QUOTA_CROSSED_SOFT_LIMIT", + "EVENT_BRICK_REPLACE", + "EVENT_BRICK_RESET", ) LAST_EVENT = "EVENT_LAST" diff --git a/heal/src/glfs-heal.c b/heal/src/glfs-heal.c index 0a880cb752e..e885dd9fe63 100644 --- a/heal/src/glfs-heal.c +++ b/heal/src/glfs-heal.c @@ -517,7 +517,7 @@ out: (*num_entries)++; glfsh_output->print_heal_status (path ? path : - uuid_utoa_r (gfid, gfid_str), + uuid_utoa_r (gfid, gfid_str), gfid, status ? status : ""); diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 6a134e84163..49c3d963578 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -198,6 +198,7 @@ enum gluster_cli_procnum { GLUSTER_CLI_DETACH_TIER, GLUSTER_CLI_TIER, GLUSTER_CLI_GET_STATE, + GLUSTER_CLI_RESET_BRICK, GLUSTER_CLI_MAXVALUE, }; diff --git a/tests/bugs/replicate/bug-1266876-allow-reset-brick-for-same-path.t b/tests/bugs/replicate/bug-1266876-allow-reset-brick-for-same-path.t new file mode 100644 index 00000000000..884b7892954 --- /dev/null +++ b/tests/bugs/replicate/bug-1266876-allow-reset-brick-for-same-path.t @@ -0,0 +1,54 @@ +#!/bin/bash +. $(dirname $0)/../../include.rc +. $(dirname $0)/../../volume.rc +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1} +TEST $CLI volume start $V0 + +TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0; +# Create files +for i in {1..5} +do + echo $i > $M0/file$i.txt +done + +# Negative case with brick not killed && volume-id xattrs present +TEST ! $CLI volume reset-brick $V0 $H0:$B0/${V0}1 $H0:$B0/${V0}1 commit force +TEST kill_brick $V0 $H0 $B0/${V0}1 + +# Negative case with brick killed but volume-id xattr present +TEST ! $CLI volume reset-brick $V0 $H0:$B0/${V0}1 $H0:$B0/${V0}1 commit + +TEST $CLI volume reset-brick $V0 $H0:$B0/${V0}1 start +# Simulated reset disk +for i in {1..5} +do + rm -rf $B0/${V0}{1}/file$i.txt +done +for i in {6..10} +do + echo $i > $M0/file$i.txt +done + +# Now reset the brick +TEST $CLI volume reset-brick $V0 $H0:$B0/${V0}1 $H0:$B0/${V0}1 commit force + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0 +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1 + +EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0 +EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1 + +TEST $CLI volume heal $V0 + +EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0 + +# Check if entry-heal has happened +TEST diff <(ls $B0/${V0}0 | sort) <(ls $B0/${V0}1 | sort) +EXPECT "10" echo $(ls $B0/${V0}1 | wc -l) + +cleanup; diff --git a/xlators/cluster/afr/src/afr-inode-write.c b/xlators/cluster/afr/src/afr-inode-write.c index ddc257dbde4..24ab52f0266 100644 --- a/xlators/cluster/afr/src/afr-inode-write.c +++ b/xlators/cluster/afr/src/afr-inode-write.c @@ -1235,8 +1235,8 @@ _afr_handle_empty_brick (void *opaque) loc_copy (&local->loc, &data->loc); - gf_msg_debug (this->name, 0, "New brick is : %s", - priv->children[empty_index]->name); + gf_msg (this->name, GF_LOG_INFO, 0, 0, "New brick is : %s", + priv->children[empty_index]->name); ret = _afr_handle_empty_brick_type (this, frame, &local->loc, empty_index, AFR_METADATA_TRANSACTION, op_type); diff --git a/xlators/mgmt/glusterd/src/Makefile.am b/xlators/mgmt/glusterd/src/Makefile.am index 23840cdb80e..faee8625d1c 100644 --- a/xlators/mgmt/glusterd/src/Makefile.am +++ b/xlators/mgmt/glusterd/src/Makefile.am @@ -16,7 +16,8 @@ glusterd_la_SOURCES = glusterd.c glusterd-handler.c glusterd-sm.c \ glusterd-proc-mgmt.c glusterd-svc-mgmt.c glusterd-shd-svc.c \ glusterd-nfs-svc.c glusterd-quotad-svc.c glusterd-svc-helper.c \ glusterd-conn-helper.c glusterd-snapd-svc.c glusterd-snapd-svc-helper.c \ - glusterd-bitd-svc.c glusterd-scrub-svc.c glusterd-server-quorum.c + glusterd-bitd-svc.c glusterd-scrub-svc.c glusterd-server-quorum.c \ + glusterd-reset-brick.c glusterd_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \ diff --git a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c index 7be1d382d5f..8458876f50f 100644 --- a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c @@ -1830,7 +1830,7 @@ glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr, dict_t *rsp_dict) brick_alloc = _gf_true; ret = glusterd_new_brick_validate (brick, brickinfo, msg, - sizeof (msg)); + sizeof (msg), NULL); if (ret) { *op_errstr = gf_strdup (msg); ret = -1; diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 4a027f4ed7d..18886dc5d15 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -5926,6 +5926,7 @@ rpcsvc_actor_t gd_svc_cli_actors[GLUSTER_CLI_MAXVALUE] = { [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}, [GLUSTER_CLI_GET_STATE] = {"GET_STATE", GLUSTER_CLI_GET_STATE, glusterd_handle_get_state, NULL, 0, DRC_NA}, + [GLUSTER_CLI_RESET_BRICK] = {"RESET_BRICK", GLUSTER_CLI_RESET_BRICK, glusterd_handle_reset_brick, NULL, 0, DRC_NA}, }; struct rpcsvc_program gd_svc_cli_prog = { diff --git a/xlators/mgmt/glusterd/src/glusterd-hooks.c b/xlators/mgmt/glusterd/src/glusterd-hooks.c index 9229da9c45f..77efa6c57b3 100644 --- a/xlators/mgmt/glusterd/src/glusterd-hooks.c +++ b/xlators/mgmt/glusterd/src/glusterd-hooks.c @@ -57,6 +57,7 @@ char glusterd_hook_dirnames[GD_OP_MAX][256] = [GD_OP_LIST_VOLUME] = EMPTY, [GD_OP_CLEARLOCKS_VOLUME] = EMPTY, [GD_OP_DEFRAG_BRICK_VOLUME] = EMPTY, + [GD_OP_RESET_BRICK] = EMPTY, }; #undef EMPTY diff --git a/xlators/mgmt/glusterd/src/glusterd-messages.h b/xlators/mgmt/glusterd/src/glusterd-messages.h index f0c9ee25ed6..e520c69add2 100644 --- a/xlators/mgmt/glusterd/src/glusterd-messages.h +++ b/xlators/mgmt/glusterd/src/glusterd-messages.h @@ -41,7 +41,7 @@ #define GLUSTERD_COMP_BASE GLFS_MSGID_GLUSTERD -#define GLFS_NUM_MESSAGES 585 +#define GLFS_NUM_MESSAGES 587 #define GLFS_MSGID_END (GLUSTERD_COMP_BASE + GLFS_NUM_MESSAGES + 1) /* Messaged with message IDs */ @@ -2837,7 +2837,7 @@ * @recommendedaction * */ -#define GD_MSG_NFS_VOL_FILE_GEN_FAIL (GLUSTERD_COMP_BASE + 349) +#define GD_MSG_GLUSTER_SERVICE_START_FAIL (GLUSTERD_COMP_BASE + 349) /*! * @messageid @@ -2965,7 +2965,7 @@ * @recommendedaction * */ -#define GD_MSG_NFS_SERVER_STOP_FAIL (GLUSTERD_COMP_BASE + 365) +#define GD_MSG_GLUSTER_SERVICES_STOP_FAIL (GLUSTERD_COMP_BASE + 365) /*! * @messageid @@ -4721,6 +4721,14 @@ */ #define GD_MSG_DAEMON_STATE_REQ_RCVD (GLUSTERD_COMP_BASE + 584) +/*! + * @messageid + * @diagnosis + * @recommendation + * + */ +#define GD_MSG_BRICK_CLEANUP_SUCCESS (GLUSTERD_COMP_BASE + 584) + /*! * @messageid * @diagnosis @@ -4729,6 +4737,21 @@ */ #define GD_MSG_STATE_STR_GET_FAILED (GLUSTERD_COMP_BASE + 585) +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define GD_MSG_RESET_BRICK_COMMIT_FORCE_REQ_RCVD (GLUSTERD_COMP_BASE + 586) + +/*! + * @messageid + * @diagnosis + * @recommendedaction + * + */ +#define GD_MSG_RESET_BRICK_CMD_FAIL (GLUSTERD_COMP_BASE + 587) /*------------*/ #define glfs_msg_end_x GLFS_MSGID_END, "Invalid: End of messages" #endif /* !_GLUSTERD_MESSAGES_H_ */ diff --git a/xlators/mgmt/glusterd/src/glusterd-mgmt.c b/xlators/mgmt/glusterd/src/glusterd-mgmt.c index 6cc7b84b8b2..a5d22e4e265 100644 --- a/xlators/mgmt/glusterd/src/glusterd-mgmt.c +++ b/xlators/mgmt/glusterd/src/glusterd-mgmt.c @@ -189,6 +189,17 @@ gd_mgmt_v3_pre_validate_fn (glusterd_op_t op, dict_t *dict, } break; + case GD_OP_RESET_BRICK: + ret = glusterd_reset_brick_prevalidate (dict, op_errstr, + rsp_dict); + if (ret) { + gf_msg (this->name, GF_LOG_WARNING, 0, + GD_MSG_PRE_VALIDATION_FAIL, + "Reset brick prevalidation failed."); + goto out; + } + break; + default: break; } @@ -298,6 +309,17 @@ gd_mgmt_v3_commit_fn (glusterd_op_t op, dict_t *dict, break; } + case GD_OP_RESET_BRICK: + { + ret = glusterd_op_reset_brick (dict, rsp_dict); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_COMMIT_OP_FAIL, + "Reset-brick commit failed."); + goto out; + } + break; + } default: break; @@ -670,6 +692,16 @@ glusterd_pre_validate_aggr_rsp_dict (glusterd_op_t op, goto out; } break; + case GD_OP_RESET_BRICK: + ret = glusterd_rb_use_rsp_dict (aggr, rsp); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_PRE_VALIDATION_FAIL, + "Failed to aggregate prevalidate " + "response dictionaries."); + goto out; + } + break; default: ret = -1; gf_msg (this->name, GF_LOG_ERROR, EINVAL, @@ -972,6 +1004,7 @@ glusterd_mgmt_v3_build_payload (dict_t **req, char **op_errstr, dict_t *dict, case GD_OP_START_VOLUME: case GD_OP_ADD_BRICK: case GD_OP_REPLACE_BRICK: + case GD_OP_RESET_BRICK: { ret = dict_get_str (dict, "volname", &volname); if (ret) { diff --git a/xlators/mgmt/glusterd/src/glusterd-mgmt.h b/xlators/mgmt/glusterd/src/glusterd-mgmt.h index bf87ec710f1..2215f178327 100644 --- a/xlators/mgmt/glusterd/src/glusterd-mgmt.h +++ b/xlators/mgmt/glusterd/src/glusterd-mgmt.h @@ -74,4 +74,10 @@ glusterd_mgmt_v3_release_peer_locks (glusterd_op_t op, dict_t *dict, int32_t glusterd_multiple_mgmt_v3_unlock (dict_t *dict, uuid_t uuid); + +int +glusterd_reset_brick_prevalidate (dict_t *dict, char **op_errstr, + dict_t *rsp_dict); +int +glusterd_op_reset_brick (dict_t *dict, dict_t *rsp_dict); #endif /* _GLUSTERD_MGMT_H_ */ diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c index 553b7b4a6cf..dc28a2b9236 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -4139,6 +4139,7 @@ glusterd_op_build_payload (dict_t **req, char **op_errstr, dict_t *op_ctx) case GD_OP_BITROT: case GD_OP_SCRUB_STATUS: case GD_OP_SCRUB_ONDEMAND: + case GD_OP_RESET_BRICK: { do_common = _gf_true; } diff --git a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c index 0df5d437ca5..687ff004eb5 100644 --- a/xlators/mgmt/glusterd/src/glusterd-replace-brick.c +++ b/xlators/mgmt/glusterd/src/glusterd-replace-brick.c @@ -27,13 +27,6 @@ #include -#define GLUSTERD_GET_RB_MNTPT(path, len, volinfo) \ - snprintf (path, len, \ - DEFAULT_VAR_RUN_DIRECTORY"/%s-"RB_CLIENT_MOUNTPOINT, \ - volinfo->volname); - -extern uuid_t global_txn_id; - int glusterd_mgmt_v3_initiate_replace_brick_cmd_phases (rpcsvc_request_t *req, glusterd_op_t op, @@ -46,14 +39,17 @@ __glusterd_handle_replace_brick (rpcsvc_request_t *req) dict_t *dict = NULL; char *src_brick = NULL; char *dst_brick = NULL; - int32_t op = 0; + char *cli_op = NULL; + glusterd_op_t op = -1; char *volname = NULL; char msg[2048] = {0,}; xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; GF_ASSERT (req); this = THIS; GF_ASSERT (this); + conf = this->private; ret = xdr_to_generic (req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req); if (ret < 0) { @@ -95,7 +91,7 @@ __glusterd_handle_replace_brick (rpcsvc_request_t *req) goto out; } - ret = dict_get_int32 (dict, "operation", &op); + ret = dict_get_str (dict, "operation", &cli_op); if (ret) { gf_msg_debug (this->name, 0, "dict_get on operation failed"); @@ -103,6 +99,19 @@ __glusterd_handle_replace_brick (rpcsvc_request_t *req) goto out; } + op = gd_cli_to_gd_op (cli_op); + + if (conf->op_version < GD_OP_VERSION_3_9_0 && + strcmp (cli_op, "GF_REPLACE_OP_COMMIT_FORCE")) { + snprintf (msg, sizeof (msg), "Cannot execute command. The " + "cluster is operating at version %d. reset-brick " + "command %s is unavailable in this version.", + conf->op_version, + gd_rb_op_to_str (cli_op)); + ret = -1; + goto out; + } + ret = dict_get_str (dict, "src-brick", &src_brick); if (ret) { @@ -114,52 +123,60 @@ __glusterd_handle_replace_brick (rpcsvc_request_t *req) gf_msg_debug (this->name, 0, "src brick=%s", src_brick); - ret = dict_get_str (dict, "dst-brick", &dst_brick); + if (!strcmp (cli_op, "GF_RESET_OP_COMMIT") || + !strcmp (cli_op, "GF_RESET_OP_COMMIT_FORCE") || + !strcmp (cli_op, "GF_REPLACE_OP_COMMIT_FORCE")) { + ret = dict_get_str (dict, "dst-brick", &dst_brick); - if (ret) { - snprintf (msg, sizeof (msg), "Failed to get dest brick"); - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_DICT_GET_FAILED, "%s", msg); - goto out; + if (ret) { + snprintf (msg, sizeof (msg), "Failed to get" + "dest brick"); + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_GET_FAILED, "%s", msg); + goto out; + } + + gf_msg_debug (this->name, 0, "dst brick=%s", dst_brick); } - gf_msg_debug (this->name, 0, "dst brick=%s", dst_brick); gf_msg (this->name, GF_LOG_INFO, 0, - GD_MSG_REPLACE_BRK_COMMIT_FORCE_REQ_RCVD, - "Received replace brick commit-force " - "request operation"); + (op == GD_OP_REPLACE_BRICK) ? + GD_MSG_REPLACE_BRK_COMMIT_FORCE_REQ_RCVD : + GD_MSG_RESET_BRICK_COMMIT_FORCE_REQ_RCVD, + "Received %s request.", + gd_rb_op_to_str (cli_op)); + + gf_event ((op == GD_OP_REPLACE_BRICK) ? EVENT_BRICK_REPLACE : + EVENT_BRICK_RESET, "received %s request. Source bricks %s," + "destination brick %s.", gd_rb_op_to_str (cli_op), + src_brick, (dst_brick) ? dst_brick : ""); ret = glusterd_mgmt_v3_initiate_replace_brick_cmd_phases (req, - GD_OP_REPLACE_BRICK, dict); + op, dict); out: + if (ret) { + glusterd_op_send_cli_response (op, ret, 0, req, + dict, msg); + } + ret = 0; free (cli_req.dict.dict_val);//malloced by xdr return ret; } int -glusterd_handle_replace_brick (rpcsvc_request_t *req) +glusterd_handle_reset_brick (rpcsvc_request_t *req) { return glusterd_big_locked_handler (req, __glusterd_handle_replace_brick); } -static int -glusterd_get_rb_dst_brickinfo (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t **brickinfo) +int +glusterd_handle_replace_brick (rpcsvc_request_t *req) { - int32_t ret = -1; - - if (!volinfo || !brickinfo) - goto out; - - *brickinfo = volinfo->rep_brick.dst_brick; - - ret = 0; - -out: - return ret; + return glusterd_big_locked_handler (req, + __glusterd_handle_replace_brick); } int @@ -170,21 +187,22 @@ glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr, char *src_brick = NULL; char *dst_brick = NULL; char *volname = NULL; - char *replace_op = NULL; + char *op = NULL; + glusterd_op_t gd_op = -1; glusterd_volinfo_t *volinfo = NULL; glusterd_brickinfo_t *src_brickinfo = NULL; char *host = NULL; char *path = NULL; char msg[2048] = {0}; - char *dup_dstbrick = NULL; glusterd_peerinfo_t *peerinfo = NULL; glusterd_brickinfo_t *dst_brickinfo = NULL; glusterd_conf_t *priv = NULL; char pidfile[PATH_MAX] = {0}; xlator_t *this = NULL; gf_boolean_t is_force = _gf_false; - gsync_status_param_t param = {0,}; - char *c = NULL; + pid_t pid = -1; + uuid_t volume_id = {0,}; + char *dup_dstbrick = NULL; this = THIS; GF_ASSERT (this); @@ -192,193 +210,41 @@ glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr, priv = this->private; GF_ASSERT (priv); - ret = dict_get_str (dict, "src-brick", &src_brick); - - if (ret) { - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_DICT_GET_FAILED, "Unable to get src brick"); - goto out; - } - - gf_msg_debug (this->name, 0, "src brick=%s", src_brick); - - ret = dict_get_str (dict, "dst-brick", &dst_brick); - - if (ret) { - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_DICT_GET_FAILED, "Unable to get dest brick"); - goto out; - } - - gf_msg_debug (this->name, 0, "dst brick=%s", dst_brick); - - ret = dict_get_str (dict, "volname", &volname); - - if (ret) { - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_DICT_GET_FAILED, "Unable to get volume name"); - goto out; - } - - ret = dict_get_str (dict, "operation", &replace_op); - if (ret) { - gf_msg_debug (this->name, 0, - "dict get on replace-brick operation failed"); - goto out; - } - - ret = glusterd_volinfo_find (volname, &volinfo); - if (ret) { - snprintf (msg, sizeof (msg), "volume: %s does not exist", - volname); - *op_errstr = gf_strdup (msg); - goto out; - } - - if (GLUSTERD_STATUS_STARTED != volinfo->status) { - ret = -1; - snprintf (msg, sizeof (msg), "volume: %s is not started", - volname); - *op_errstr = gf_strdup (msg); - goto out; - } - - ret = glusterd_disallow_op_for_tier (volinfo, GD_OP_REPLACE_BRICK, -1); - if (ret) { - snprintf (msg, sizeof (msg), "Replace brick commands are not " - "supported on tiered volume %s", volname); - *op_errstr = gf_strdup (msg); - goto out; - } - - if (!glusterd_store_is_valid_brickpath (volname, dst_brick) || - !glusterd_is_valid_volfpath (volname, dst_brick)) { - snprintf (msg, sizeof (msg), "brick path %s is too " - "long.", dst_brick); - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_BRKPATH_TOO_LONG, "%s", msg); - *op_errstr = gf_strdup (msg); - - ret = -1; - goto out; - } - - /* If geo-rep is configured, for this volume, it should be stopped. */ - param.volinfo = volinfo; - ret = glusterd_check_geo_rep_running (¶m, op_errstr); - if (ret || param.is_active) { - ret = -1; + ret = glusterd_brick_op_prerequisites (dict, &op, &gd_op, + &volname, &volinfo, + &src_brick, &src_brickinfo, + pidfile, + op_errstr, rsp_dict); + if (ret) goto out; - } - if (glusterd_is_defrag_on(volinfo)) { - snprintf (msg, sizeof(msg), "Volume name %s rebalance is in " - "progress. Please retry after completion", volname); - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_OIP_RETRY_LATER, "%s", msg); - *op_errstr = gf_strdup (msg); + if (strcmp (op, "GF_REPLACE_OP_COMMIT_FORCE")) { ret = -1; goto out; - } - - if (!strcmp(replace_op, "GF_REPLACE_OP_COMMIT_FORCE")) { - is_force = _gf_true; } else { - ret = -1; - goto out; - } - - ret = glusterd_volume_brickinfo_get_by_brick (src_brick, volinfo, - &src_brickinfo, - _gf_false); - if (ret) { - snprintf (msg, sizeof (msg), "brick: %s does not exist in " - "volume: %s", src_brick, volname); - *op_errstr = gf_strdup (msg); - goto out; - } - - if (dict) { - if (!glusterd_is_fuse_available ()) { - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_RB_CMD_FAIL, "Unable to open /dev/" - "fuse (%s), replace-brick command failed", - strerror (errno)); - snprintf (msg, sizeof(msg), "Fuse unavailable\n " - "Replace-brick failed"); - *op_errstr = gf_strdup (msg); - ret = -1; - goto out; - } - } - - if (gf_is_local_addr (src_brickinfo->hostname)) { - gf_msg_debug (this->name, 0, - "I AM THE SOURCE HOST"); - if (src_brickinfo->port && rsp_dict) { - ret = dict_set_int32 (rsp_dict, "src-brick-port", - src_brickinfo->port); - if (ret) { - gf_msg_debug (this->name, 0, - "Could not set src-brick-port=%d", - src_brickinfo->port); - } - } - - GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, src_brickinfo, - priv); - - } - - dup_dstbrick = gf_strdup (dst_brick); - if (!dup_dstbrick) { - ret = -1; - gf_msg (this->name, GF_LOG_ERROR, ENOMEM, - GD_MSG_NO_MEMORY, "Memory allocation failed"); - goto out; - } - - /* - * IPv4 address contains '.' and ipv6 addresses contains ':' - * So finding the last occurance of ':' to - * mark the start of brick path - */ - c = strrchr(dup_dstbrick, ':'); - if (c != NULL) { - c[0] = '\0'; - host = dup_dstbrick; - path = c++; - } - - if (!host || !path) { - gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_BAD_FORMAT, - "dst brick %s is not of form :", - dst_brick); - ret = -1; - goto out; - } + is_force = _gf_true; + } - ret = glusterd_brickinfo_new_from_brick (dst_brick, &dst_brickinfo, - _gf_true, NULL); + ret = glusterd_get_dst_brick_info (&dst_brick, volname, + op_errstr, + &dst_brickinfo, &host, + dict, &dup_dstbrick); if (ret) goto out; ret = glusterd_new_brick_validate (dst_brick, dst_brickinfo, - msg, sizeof (msg)); - if (ret) { + msg, sizeof (msg), op); + /* fail if brick being replaced with itself */ + if (ret) { *op_errstr = gf_strdup (msg); ret = -1; gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_BRICK_VALIDATE_FAIL, "%s", *op_errstr); goto out; - } + } - if (!strcmp(replace_op, "GF_REPLACE_OP_COMMIT_FORCE")) { - - volinfo->rep_brick.src_brick = src_brickinfo; - volinfo->rep_brick.dst_brick = dst_brickinfo; - } + volinfo->rep_brick.src_brick = src_brickinfo; + volinfo->rep_brick.dst_brick = dst_brickinfo; if (glusterd_rb_check_bricks (volinfo, src_brickinfo, dst_brickinfo)) { @@ -484,48 +350,8 @@ rb_kill_destination_brick (glusterd_volinfo_t *volinfo, return glusterd_service_stop ("brick", pidfile, SIGTERM, _gf_true); } -static int -rb_update_dstbrick_port (glusterd_brickinfo_t *dst_brickinfo, dict_t *rsp_dict, - dict_t *req_dict, char *replace_op) -{ - int ret = 0; - int dict_ret = 0; - int dst_port = 0; - - dict_ret = dict_get_int32 (req_dict, "dst-brick-port", &dst_port); - if (!dict_ret) - dst_brickinfo->port = dst_port; - - if (gf_is_local_addr (dst_brickinfo->hostname)) { - gf_msg ("glusterd", GF_LOG_INFO, 0, - GD_MSG_BRK_PORT_NO_ADD_INDO, - "adding dst-brick port no"); - - if (rsp_dict) { - ret = dict_set_int32 (rsp_dict, "dst-brick-port", - dst_brickinfo->port); - if (ret) { - gf_msg_debug ("glusterd", 0, - "Could not set dst-brick port no in rsp dict"); - goto out; - } - } - - if (req_dict) { - ret = dict_set_int32 (req_dict, "dst-brick-port", - dst_brickinfo->port); - if (ret) { - gf_msg_debug ("glusterd", 0, - "Could not set dst-brick port no"); - goto out; - } - } - } -out: - return ret; -} -static int +int glusterd_op_perform_replace_brick (glusterd_volinfo_t *volinfo, char *old_brick, char *new_brick, dict_t *dict) @@ -563,6 +389,7 @@ glusterd_op_perform_replace_brick (glusterd_volinfo_t *volinfo, strncpy (new_brickinfo->brick_id, old_brickinfo->brick_id, sizeof (new_brickinfo->brick_id)); + new_brickinfo->port = old_brickinfo->port; /* A bricks mount dir is required only by snapshots which were * introduced in gluster-3.6.0 @@ -579,8 +406,8 @@ glusterd_op_perform_replace_brick (glusterd_volinfo_t *volinfo, sizeof(new_brickinfo->mount_dir)); } - cds_list_add_tail (&new_brickinfo->brick_list, - &old_brickinfo->brick_list); + cds_list_add (&new_brickinfo->brick_list, + &old_brickinfo->brick_list); volinfo->brick_count++; @@ -699,11 +526,11 @@ glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict) } ret = rb_update_dstbrick_port (dst_brickinfo, rsp_dict, - dict, replace_op); + dict); if (ret) goto out; - if (strcmp(replace_op, "GF_REPLACE_OP_COMMIT_FORCE")) { + if (strcmp (replace_op, "GF_REPLACE_OP_COMMIT_FORCE")) { ret = -1; goto out; } @@ -722,8 +549,8 @@ glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict) ret = glusterd_svcs_stop (volinfo); if (ret) { gf_msg (this->name, GF_LOG_ERROR, 0, - GD_MSG_NFS_SERVER_STOP_FAIL, - "Unable to stop nfs server, ret: %d", ret); + GD_MSG_GLUSTER_SERVICES_STOP_FAIL, + "Unable to stop gluster services, ret: %d", ret); } ret = glusterd_op_perform_replace_brick (volinfo, src_brick, @@ -732,7 +559,7 @@ glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict) gf_msg (this->name, GF_LOG_CRITICAL, 0, GD_MSG_BRICK_ADD_FAIL, "Unable to add dst-brick: " "%s to volume: %s", dst_brick, volinfo->volname); - (void) glusterd_svcs_manager (volinfo); + (void) glusterd_svcs_manager (volinfo); goto out; } @@ -741,8 +568,8 @@ glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict) ret = glusterd_svcs_manager (volinfo); if (ret) { gf_msg (this->name, GF_LOG_CRITICAL, 0, - GD_MSG_NFS_VOL_FILE_GEN_FAIL, - "Failed to generate nfs volume file"); + GD_MSG_GLUSTER_SERVICE_START_FAIL, + "Failed to start one or more gluster services."); } @@ -752,7 +579,7 @@ glusterd_op_replace_brick (dict_t *dict, dict_t *rsp_dict) volinfo->rep_brick.dst_brick = NULL; if (!ret) - ret = glusterd_store_volinfo (volinfo, + ret = glusterd_store_volinfo (volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT); if (ret) gf_msg (this->name, GF_LOG_ERROR, 0, diff --git a/xlators/mgmt/glusterd/src/glusterd-reset-brick.c b/xlators/mgmt/glusterd/src/glusterd-reset-brick.c new file mode 100644 index 00000000000..d1efe0663fb --- /dev/null +++ b/xlators/mgmt/glusterd/src/glusterd-reset-brick.c @@ -0,0 +1,430 @@ +/* + Copyright (c) 2016 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. +*/ +#include "common-utils.h" +#include "cli1-xdr.h" +#include "xdr-generic.h" +#include "glusterfs.h" +#include "glusterd.h" +#include "glusterd-op-sm.h" +#include "glusterd-geo-rep.h" +#include "glusterd-store.h" +#include "glusterd-utils.h" +#include "glusterd-svc-mgmt.h" +#include "glusterd-svc-helper.h" +#include "glusterd-nfs-svc.h" +#include "glusterd-volgen.h" +#include "glusterd-messages.h" +#include "glusterd-mgmt.h" +#include "run.h" +#include "syscall.h" + +#include + +int +glusterd_reset_brick_prevalidate (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int ret = 0; + int32_t port = 0; + char *src_brick = NULL; + char *dst_brick = NULL; + char *volname = NULL; + char *op = NULL; + glusterd_op_t gd_op = -1; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *src_brickinfo = NULL; + char *host = NULL; + char msg[2048] = {0}; + glusterd_peerinfo_t *peerinfo = NULL; + glusterd_brickinfo_t *dst_brickinfo = NULL; + gf_boolean_t enabled = _gf_false; + glusterd_conf_t *priv = NULL; + char *savetok = NULL; + char pidfile[PATH_MAX] = {0}; + char *task_id_str = NULL; + xlator_t *this = NULL; + gf_boolean_t is_force = _gf_false; + gsync_status_param_t param = {0,}; + pid_t pid = -1; + uuid_t volume_id = {0,}; + char *dup_dstbrick = NULL; + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + GF_ASSERT (priv); + + ret = glusterd_brick_op_prerequisites (dict, &op, &gd_op, + &volname, &volinfo, + &src_brick, &src_brickinfo, + pidfile, + op_errstr, rsp_dict); + if (ret) + goto out; + + if (!strcmp (op, "GF_RESET_OP_START")) + goto done; + + if (!strcmp (op, "GF_RESET_OP_COMMIT_FORCE")) + is_force = _gf_true; + + ret = glusterd_get_dst_brick_info (&dst_brick, volname, + op_errstr, + &dst_brickinfo, &host, + dict, &dup_dstbrick); + if (ret) + goto out; + + ret = glusterd_new_brick_validate (dst_brick, dst_brickinfo, + msg, sizeof (msg), op); + /* if bricks are not same and reset brick was used, fail command. + * Only replace brick should be used to replace with new bricks + * to the volume. + */ + if (ret == 0) { + if (!gf_uuid_compare (MY_UUID, dst_brickinfo->uuid)) { + ret = -1; + *op_errstr = gf_strdup + ("When destination brick is new," + " please use" + " gluster volume " + "replace-brick " + " " + "commit force"); + if (*op_errstr) + gf_msg (this->name, + GF_LOG_ERROR, + EPERM, + GD_MSG_BRICK_VALIDATE_FAIL, + "%s", *op_errstr); + goto out; + } + } else if (ret == 1) { + if (gf_is_service_running (pidfile, &pid)) { + ret = -1; + *op_errstr = gf_strdup + ("Source brick" + " must be stopped." + " Please use " + "gluster volume " + "reset-brick " + " start."); + if (*op_errstr) + gf_msg (this->name, + GF_LOG_ERROR, + EPERM, + GD_MSG_BRICK_VALIDATE_FAIL, + "%s", *op_errstr); + goto out; + } + ret = sys_lgetxattr (dst_brickinfo->path, + GF_XATTR_VOL_ID_KEY, + volume_id, 16); + if (gf_uuid_compare (dst_brickinfo->uuid, + src_brickinfo->uuid) || + (ret >= 0 && is_force == _gf_false)) { + ret = -1; + *op_errstr = gf_strdup ("Brick not available." + "It may be containing " + "or be contained " + "by an existing brick." + "Use 'force' option to " + "override this."); + if (*op_errstr) + gf_msg (this->name, + GF_LOG_ERROR, + EPERM, + GD_MSG_BRICK_VALIDATE_FAIL, + "%s", *op_errstr); + goto out; + } + ret = 0; + } else { + *op_errstr = gf_strdup (msg); + ret = -1; + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_BRICK_VALIDATE_FAIL, "%s", *op_errstr); + goto out; + } + + volinfo->rep_brick.src_brick = src_brickinfo; + volinfo->rep_brick.dst_brick = dst_brickinfo; + + if (gf_is_local_addr (host)) { + ret = glusterd_validate_and_create_brickpath + (dst_brickinfo, + volinfo->volume_id, + op_errstr, is_force); + if (ret) + goto out; + } else { + rcu_read_lock (); + + peerinfo = glusterd_peerinfo_find (NULL, host); + if (peerinfo == NULL) { + ret = -1; + snprintf (msg, sizeof (msg), + "%s, is not a friend.", + host); + *op_errstr = gf_strdup (msg); + + } else if (!peerinfo->connected) { + snprintf (msg, sizeof (msg), "%s," + "is not connected at " + "the moment.", host); + *op_errstr = gf_strdup (msg); + ret = -1; + + } else if (GD_FRIEND_STATE_BEFRIENDED != + peerinfo->state.state) { + snprintf (msg, sizeof (msg), + "%s, is not befriended " + "at the moment.", host); + *op_errstr = gf_strdup (msg); + ret = -1; + } + rcu_read_unlock (); + + if (ret) + goto out; + + } + + ret = glusterd_get_brick_mount_dir + (dst_brickinfo->path, + dst_brickinfo->hostname, + dst_brickinfo->mount_dir); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_BRICK_MOUNTDIR_GET_FAIL, + "Failed to get brick mount_dir."); + goto out; + } + + ret = dict_set_dynstr_with_alloc (rsp_dict, + "brick1.mount_dir", + dst_brickinfo->mount_dir); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_SET_FAILED, + "Failed to set brick1.mount_dir"); + goto out; + } + + ret = dict_set_int32 (rsp_dict, "brick_count", 1); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_SET_FAILED, + "Failed to set local_brick_count."); + goto out; + } + +done: + ret = 0; +out: + GF_FREE (dup_dstbrick); + gf_msg_debug (this->name, 0, "Returning %d.", ret); + + return ret; +} + +int +glusterd_op_reset_brick (dict_t *dict, dict_t *rsp_dict) +{ + int ret = 0; + dict_t *ctx = NULL; + char *op = NULL; + glusterd_volinfo_t *volinfo = NULL; + char *volname = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + char *src_brick = NULL; + char *dst_brick = NULL; + glusterd_brickinfo_t *src_brickinfo = NULL; + glusterd_brickinfo_t *dst_brickinfo = NULL; + char *task_id_str = NULL; + char pidfile[PATH_MAX] = {0,}; + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_str (dict, "operation", &op); + if (ret) { + gf_msg_debug (this->name, 0, + "dict_get on operation failed"); + goto out; + } + + ret = dict_get_str (dict, "volname", &volname); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_GET_FAILED, "Unable to get volume name"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) + goto out; + + ret = dict_get_str (dict, "src-brick", &src_brick); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_GET_FAILED, "Unable to get src brick"); + goto out; + } + + gf_msg_debug (this->name, 0, "src brick=%s", src_brick); + + ret = glusterd_volume_brickinfo_get_by_brick (src_brick, volinfo, + &src_brickinfo, + _gf_false); + if (ret) { + gf_msg_debug (this->name, 0, + "Unable to get src-brickinfo"); + goto out; + } + + if (!strcmp (op, "GF_RESET_OP_START")) { + (void) glusterd_brick_disconnect (src_brickinfo); + GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, + src_brickinfo, priv); + ret = glusterd_service_stop ("brick", pidfile, + SIGTERM, _gf_false); + if (ret == 0) { + glusterd_set_brick_status (src_brickinfo, + GF_BRICK_STOPPED); + (void) glusterd_brick_unlink_socket_file + (volinfo, src_brickinfo); + gf_msg (this->name, GF_LOG_INFO, 0, + GD_MSG_BRICK_CLEANUP_SUCCESS, + "Brick cleanup successful."); + } else { + gf_msg (this->name, GF_LOG_CRITICAL, 0, + GD_MSG_BRK_CLEANUP_FAIL, + "Unable to cleanup src brick"); + goto out; + } + goto out; + } else if (!strcmp (op, "GF_RESET_OP_COMMIT") || + !strcmp (op, "GF_RESET_OP_COMMIT_FORCE")) { + ret = dict_get_str (dict, "dst-brick", &dst_brick); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_GET_FAILED, + "Unable to get dst brick"); + goto out; + } + + gf_msg_debug (this->name, 0, "dst brick=%s", dst_brick); + + ret = glusterd_get_rb_dst_brickinfo (volinfo, + &dst_brickinfo); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_RB_BRICKINFO_GET_FAIL, + "Unable to get " + "reset brick " + "destination brickinfo"); + goto out; + } + + ret = glusterd_resolve_brick (dst_brickinfo); + if (ret) { + gf_msg_debug (this->name, 0, + "Unable to resolve dst-brickinfo"); + goto out; + } + + ret = rb_update_dstbrick_port (dst_brickinfo, rsp_dict, + dict); + if (ret) + goto out; + + if (gf_is_local_addr (dst_brickinfo->hostname)) { + gf_msg_debug (this->name, 0, "I AM THE DESTINATION HOST"); + (void) glusterd_brick_disconnect (src_brickinfo); + GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, + src_brickinfo, priv); + ret = glusterd_service_stop ("brick", pidfile, + SIGTERM, _gf_false); + if (ret == 0) { + glusterd_set_brick_status + (src_brickinfo, GF_BRICK_STOPPED); + (void) glusterd_brick_unlink_socket_file + (volinfo, src_brickinfo); + gf_msg (this->name, GF_LOG_INFO, 0, + GD_MSG_BRICK_CLEANUP_SUCCESS, + "Brick cleanup successful."); + } else { + gf_msg (this->name, GF_LOG_CRITICAL, 0, + GD_MSG_BRK_CLEANUP_FAIL, + "Unable to cleanup src brick"); + goto out; + } + } + + ret = glusterd_svcs_stop (volinfo); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_GLUSTER_SERVICES_STOP_FAIL, + "Unable to stop gluster services, ret: %d", + ret); + goto out; + } + ret = glusterd_op_perform_replace_brick (volinfo, src_brick, + dst_brick, dict); + if (ret) { + gf_msg (this->name, GF_LOG_CRITICAL, 0, + GD_MSG_BRICK_ADD_FAIL, + "Unable to add dst-brick: " + "%s to volume: %s", dst_brick, + volinfo->volname); + (void) glusterd_svcs_manager (volinfo); + goto out; + } + + volinfo->rebal.defrag_status = 0; + + ret = glusterd_svcs_manager (volinfo); + if (ret) { + gf_msg (this->name, GF_LOG_CRITICAL, 0, + GD_MSG_GLUSTER_SERVICE_START_FAIL, + "Failed to start one or more gluster services."); + } + + + ret = glusterd_fetchspec_notify (THIS); + glusterd_brickinfo_delete (volinfo->rep_brick.dst_brick); + volinfo->rep_brick.src_brick = NULL; + volinfo->rep_brick.dst_brick = NULL; + + if (!ret) + ret = glusterd_store_volinfo (volinfo, + GLUSTERD_VOLINFO_VER_AC_INCREMENT); + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_RBOP_STATE_STORE_FAIL, + "Couldn't store" + " reset brick operation's state."); + + } + } else { + ret = -1; + goto out; + } + + +out: + return ret; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c index 03b6e71cd9a..f9e76f3fad5 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c @@ -144,6 +144,7 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret, case GD_OP_BITROT: case GD_OP_SCRUB_STATUS: case GD_OP_SCRUB_ONDEMAND: + case GD_OP_RESET_BRICK: { /*nothing specific to be done*/ break; diff --git a/xlators/mgmt/glusterd/src/glusterd-syncop.c b/xlators/mgmt/glusterd/src/glusterd-syncop.c index 70d10208584..2b7a4477fca 100644 --- a/xlators/mgmt/glusterd/src/glusterd-syncop.c +++ b/xlators/mgmt/glusterd/src/glusterd-syncop.c @@ -248,6 +248,7 @@ glusterd_syncop_aggr_rsp_dict (glusterd_op_t op, dict_t *aggr, dict_t *rsp) break; case GD_OP_REPLACE_BRICK: + case GD_OP_RESET_BRICK: ret = glusterd_rb_use_rsp_dict (aggr, rsp); if (ret) goto out; diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index ec371d80815..0011cac0078 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -5970,7 +5970,7 @@ glusterd_is_defrag_on (glusterd_volinfo_t *volinfo) int glusterd_new_brick_validate (char *brick, glusterd_brickinfo_t *brickinfo, - char *op_errstr, size_t len) + char *op_errstr, size_t len, char *op) { glusterd_brickinfo_t *newbrickinfo = NULL; int ret = -1; @@ -6011,8 +6011,12 @@ glusterd_new_brick_validate (char *brick, glusterd_brickinfo_t *brickinfo, newbrickinfo->path)) { snprintf(op_errstr, len, "Brick: %s not available." " Brick may be containing or be contained " - "by an existing brick", brick); - ret = -1; + "by an existing brick.", brick); + if (op && (!strcmp (op, "GF_RESET_OP_COMMIT") || + !strcmp (op, "GF_RESET_OP_COMMIT_FORCE"))) + ret = 1; + else + ret = -1; goto out; } @@ -11458,6 +11462,7 @@ glusterd_disallow_op_for_tier (glusterd_volinfo_t *volinfo, glusterd_op_t op, switch (op) { case GD_OP_ADD_BRICK: case GD_OP_REPLACE_BRICK: + case GD_OP_RESET_BRICK: ret = -1; gf_msg_debug (this->name, 0, "Operation not " "permitted on tiered volume %s", @@ -11708,3 +11713,319 @@ get_last_brick_of_brick_group (glusterd_volinfo_t *volinfo, return last; } + +int +glusterd_get_rb_dst_brickinfo (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t **brickinfo) +{ + int32_t ret = -1; + + if (!volinfo || !brickinfo) + goto out; + + *brickinfo = volinfo->rep_brick.dst_brick; + + ret = 0; + +out: + return ret; +} + +int +rb_update_dstbrick_port (glusterd_brickinfo_t *dst_brickinfo, dict_t *rsp_dict, + dict_t *req_dict) +{ + int ret = 0; + int dict_ret = 0; + int dst_port = 0; + + dict_ret = dict_get_int32 (req_dict, "dst-brick-port", &dst_port); + if (!dict_ret) + dst_brickinfo->port = dst_port; + + if (gf_is_local_addr (dst_brickinfo->hostname)) { + gf_msg ("glusterd", GF_LOG_INFO, 0, + GD_MSG_BRK_PORT_NO_ADD_INDO, + "adding dst-brick port no %d", dst_port); + + if (rsp_dict) { + ret = dict_set_int32 (rsp_dict, "dst-brick-port", + dst_brickinfo->port); + if (ret) { + gf_msg_debug ("glusterd", 0, + "Could not set dst-brick port no in rsp dict"); + goto out; + } + } + + if (req_dict && !dict_ret) { + ret = dict_set_int32 (req_dict, "dst-brick-port", + dst_brickinfo->port); + if (ret) { + gf_msg_debug ("glusterd", 0, + "Could not set dst-brick port no"); + goto out; + } + } + } +out: + return ret; +} + +int +glusterd_brick_op_prerequisites (dict_t *dict, + char **op, + glusterd_op_t *gd_op, char **volname, + glusterd_volinfo_t **volinfo, + char **src_brick, glusterd_brickinfo_t + **src_brickinfo, char *pidfile, + char **op_errstr, dict_t *rsp_dict) +{ + int ret = 0; + char msg[2048] = {0}; + gsync_status_param_t param = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *v = NULL; + glusterd_brickinfo_t *b = NULL; + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_str (dict, "operation", op); + if (ret) { + gf_msg_debug (this->name, 0, + "dict get on operation type failed"); + goto out; + } + + *gd_op = gd_cli_to_gd_op (*op); + if (*gd_op < 0) + goto out; + + ret = dict_get_str (dict, "volname", volname); + + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_GET_FAILED, "Unable to get volume name"); + goto out; + } + + ret = glusterd_volinfo_find (*volname, volinfo); + if (ret) { + snprintf (msg, sizeof (msg), "volume: %s does not exist", + *volname); + *op_errstr = gf_strdup (msg); + goto out; + } + + if (GLUSTERD_STATUS_STARTED != (*volinfo)->status) { + ret = -1; + snprintf (msg, sizeof (msg), "volume: %s is not started", + *volname); + *op_errstr = gf_strdup (msg); + goto out; + } + + ret = glusterd_disallow_op_for_tier (*volinfo, *gd_op, -1); + if (ret) { + snprintf (msg, sizeof (msg), "%sbrick commands are not " + "supported on tiered volume %s", + (*gd_op == GD_OP_REPLACE_BRICK) ? "replace-" : + "reset-", + *volname); + *op_errstr = gf_strdup (msg); + goto out; + } + + /* If geo-rep is configured, for this volume, it should be stopped. */ + param.volinfo = *volinfo; + ret = glusterd_check_geo_rep_running (¶m, op_errstr); + if (ret || param.is_active) { + ret = -1; + goto out; + } + + if (glusterd_is_defrag_on(*volinfo)) { + snprintf (msg, sizeof(msg), "Volume name %s rebalance is in " + "progress. Please retry after completion", *volname); + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_OIP_RETRY_LATER, "%s", msg); + *op_errstr = gf_strdup (msg); + ret = -1; + goto out; + } + + if (dict) { + if (!glusterd_is_fuse_available ()) { + gf_msg (this->name, GF_LOG_ERROR, 0, + (*gd_op == GD_OP_REPLACE_BRICK) ? + GD_MSG_RB_CMD_FAIL : + GD_MSG_RESET_BRICK_CMD_FAIL, + "Unable to open /dev/" + "fuse (%s), %s command failed", + strerror (errno), gd_rb_op_to_str (*op)); + snprintf (msg, sizeof(msg), "Fuse unavailable\n " + "%s failed", gd_rb_op_to_str (*op)); + *op_errstr = gf_strdup (msg); + ret = -1; + goto out; + } + } + + ret = dict_get_str (dict, "src-brick", src_brick); + + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_GET_FAILED, "Unable to get src brick"); + goto out; + } + + gf_msg_debug (this->name, 0, "src brick=%s", *src_brick); + + ret = glusterd_volume_brickinfo_get_by_brick (*src_brick, *volinfo, + src_brickinfo, + _gf_false); + if (ret) { + snprintf (msg, sizeof (msg), "brick: %s does not exist in " + "volume: %s", *src_brick, *volname); + *op_errstr = gf_strdup (msg); + goto out; + } + + if (gf_is_local_addr ((*src_brickinfo)->hostname)) { + gf_msg_debug (this->name, 0, + "I AM THE SOURCE HOST"); + if ((*src_brickinfo)->port && rsp_dict) { + ret = dict_set_int32 (rsp_dict, "src-brick-port", + (*src_brickinfo)->port); + if (ret) { + gf_msg_debug (this->name, 0, + "Could not set src-brick-port=%d", + (*src_brickinfo)->port); + } + } + + v = *volinfo; + b = *src_brickinfo; + GLUSTERD_GET_BRICK_PIDFILE (pidfile, v, b, + priv); + } + + ret = 0; +out: + return ret; +} + +int +glusterd_get_dst_brick_info (char **dst_brick, char *volname, char **op_errstr, + glusterd_brickinfo_t **dst_brickinfo, char **host, + dict_t *dict, char **dup_dstbrick) +{ + + char *path = NULL; + char *c = NULL; + char msg[2048] = {0}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + int ret = 0; + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_str (dict, "dst-brick", dst_brick); + + if (ret) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_DICT_GET_FAILED, + "Unable to get dest brick."); + goto out; + } + + gf_msg_debug (this->name, 0, "dst brick=%s", *dst_brick); + + if (!glusterd_store_is_valid_brickpath (volname, *dst_brick) || + !glusterd_is_valid_volfpath (volname, *dst_brick)) { + snprintf (msg, sizeof (msg), "brick path %s is too " + "long.", *dst_brick); + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_BRKPATH_TOO_LONG, "%s", msg); + *op_errstr = gf_strdup (msg); + + ret = -1; + goto out; + } + + *dup_dstbrick = gf_strdup (*dst_brick); + if (!*dup_dstbrick) { + ret = -1; + goto out; + } + + /* + * IPv4 address contains '.' and ipv6 addresses contains ':' + * So finding the last occurance of ':' to + * mark the start of brick path + */ + c = strrchr(*dup_dstbrick, ':'); + if (c != NULL) { + c[0] = '\0'; + *host = *dup_dstbrick; + path = c++; + } + + if (!host || !path) { + gf_msg (this->name, GF_LOG_ERROR, 0, + GD_MSG_BAD_FORMAT, + "dst brick %s is not of " + "form :", + *dst_brick); + ret = -1; + goto out; + } + + ret = glusterd_brickinfo_new_from_brick (*dst_brick, + dst_brickinfo, + _gf_true, NULL); + if (ret) + goto out; + + ret = 0; +out: + return ret; +} + +glusterd_op_t +gd_cli_to_gd_op (char *cli_op) +{ + if (!strcmp (cli_op, "GF_RESET_OP_START") || + !strcmp(cli_op, "GF_RESET_OP_COMMIT") || + !strcmp (cli_op, "GF_RESET_OP_COMMIT_FORCE")) { + return GD_OP_RESET_BRICK; + } + + if (!strcmp (cli_op, "GF_REPLACE_OP_COMMIT_FORCE")) + return GD_OP_REPLACE_BRICK; + + return -1; +} + +char * +gd_rb_op_to_str (char *op) +{ + if (!strcmp (op, "GF_RESET_OP_START")) + return "reset-brick start"; + if (!strcmp (op, "GF_RESET_OP_COMMIT")) + return "reset-brick commit"; + if (!strcmp (op, "GF_RESET_OP_COMMIT_FORCE")) + return "reset-brick commit force"; + if (!strcmp (op, "GF_REPLACE_OP_COMMIT_FORCE")) + return "replace-brick commit force"; + return NULL; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index ca07efd54ba..419ab48323a 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -242,7 +242,7 @@ glusterd_volinfo_bricks_delete (glusterd_volinfo_t *volinfo); int glusterd_new_brick_validate (char *brick, glusterd_brickinfo_t *brickinfo, - char *op_errstr, size_t len); + char *op_errstr, size_t len, char *op); int32_t glusterd_volume_brickinfos_delete (glusterd_volinfo_t *volinfo); @@ -741,4 +741,36 @@ assign_brick_groups (glusterd_volinfo_t *volinfo); glusterd_brickinfo_t* get_last_brick_of_brick_group (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo); +int +glusterd_get_rb_dst_brickinfo (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t **brickinfo); +int +rb_update_dstbrick_port (glusterd_brickinfo_t *dst_brickinfo, dict_t *rsp_dict, + dict_t *req_dict); +int +glusterd_op_perform_replace_brick (glusterd_volinfo_t *volinfo, + char *old_brick, char *new_brick, + dict_t *dict); +int32_t +glusterd_brick_unlink_socket_file (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo); +char * +gd_rb_op_to_str (char *op); + +glusterd_op_t +gd_cli_to_gd_op (char *cli_op); + +int +glusterd_get_dst_brick_info (char **dst_brick, char *volname, char **op_errstr, + glusterd_brickinfo_t **dst_brickinfo, char **host, + dict_t *dict, char **dup_dstbrick); + +int +glusterd_brick_op_prerequisites (dict_t *dict, + char **op, + glusterd_op_t *gd_op, char **volname, + glusterd_volinfo_t **volinfo, + char **src_brick, glusterd_brickinfo_t + **src_brickinfo, char *pidfile, + char **op_errstr, dict_t *rsp_dict); #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c index fe5d4c8e348..b38b0e6960e 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c @@ -1253,7 +1253,7 @@ glusterd_op_stage_create_volume (dict_t *dict, char **op_errstr, goto out; ret = glusterd_new_brick_validate (brick, brick_info, msg, - sizeof (msg)); + sizeof (msg), NULL); if (ret) goto out; diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c index 7d108276cb4..705ce721ea8 100644 --- a/xlators/mgmt/glusterd/src/glusterd.c +++ b/xlators/mgmt/glusterd/src/glusterd.c @@ -123,6 +123,7 @@ const char *gd_op_list[GD_OP_MAX + 1] = { [GD_OP_SYS_EXEC] = "Execute system commands", [GD_OP_GSYNC_CREATE] = "Geo-replication Create", [GD_OP_SNAP] = "Snapshot", + [GD_OP_RESET_BRICK] = "Reset Brick", [GD_OP_MAX] = "Invalid op" }; diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 430798f5fbd..eb03d05b6d9 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -119,6 +119,7 @@ typedef enum glusterd_op_ { GD_OP_TIER_MIGRATE, GD_OP_SCRUB_STATUS, GD_OP_SCRUB_ONDEMAND, + GD_OP_RESET_BRICK, GD_OP_MAX, } glusterd_op_t; @@ -949,6 +950,9 @@ glusterd_handle_bitrot (rpcsvc_request_t *req); int glusterd_handle_fsm_log (rpcsvc_request_t *req); +int +glusterd_handle_reset_brick (rpcsvc_request_t *req); + int glusterd_xfer_cli_deprobe_resp (rpcsvc_request_t *req, int32_t op_ret, int32_t op_errno, char *op_errstr, @@ -1192,4 +1196,6 @@ int glusterd_remove_brick_migrate_cbk (glusterd_volinfo_t *volinfo, gf_defrag_status_t status); +int +__glusterd_handle_reset_brick (rpcsvc_request_t *req); #endif -- cgit