From 005b445d684f30e8611c9b2a374cdc798a6cdcbb Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Fri, 29 Nov 2013 12:29:38 +0530 Subject: cli/glusterd: implement the snap and cg delete functionalities Change-Id: Icdb66c89acdd043d0d6368c48ce2e01b1a40966f Signed-off-by: Raghavendra Bhat --- cli/src/cli-cmd-parser.c | 287 +++++--- cli/src/cli-cmd-snapshot.c | 4 + cli/src/cli-rpc-ops.c | 61 ++ xlators/mgmt/glusterd/src/glusterd-snapshot.c | 966 ++++++++++++++++++++++---- xlators/mgmt/glusterd/src/glusterd-utils.c | 186 +++++ xlators/mgmt/glusterd/src/glusterd-utils.h | 9 + xlators/mgmt/glusterd/src/glusterd-volgen.c | 33 + xlators/mgmt/glusterd/src/glusterd-volgen.h | 4 + 8 files changed, 1334 insertions(+), 216 deletions(-) diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 4bbaa4923..d1afa72a4 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -3256,6 +3256,97 @@ out: return ret; } +/* remove command takes either the snapname or the cg name. + If snap has to be remvoed for a volume, then the volume name + also should be given in the command. If cg should be removed, + then volume name is not necessary. + "gluster snapshot delete ( -s | -c )" +*/ +int32_t +cli_snap_remove_parse (dict_t *dict, const char **words, int wordcount, + unsigned int cmdi) +{ + uint32_t name_opt_loc = 0; + int32_t ret = -1; + uint32_t i = 0; + gf_boolean_t is_cg = _gf_false; + + GF_ASSERT (dict); + GF_ASSERT (words); + + /* Finding the "-s or -c" in the cli */ + for (i = cmdi; i < wordcount; i++) { + if (!strcmp (words[i], "-s") || !strcmp (words[i], "-c")) { + name_opt_loc = i; + if (!strcmp (words[i], "-c")) + is_cg = _gf_true; + break; + } + } + + if (name_opt_loc == 0) { + gf_log ("", GF_LOG_ERROR, "options -s/-c is not found in the " + "command"); + goto out; + } + + if (name_opt_loc == (wordcount - 1)) { + gf_log ("", GF_LOG_ERROR, "%s name is not given", + is_cg?"cg":"snap"); + goto out; + } + + if (!is_cg) { + if (!strcmp (words[cmdi], "-s")) { + gf_log ("", GF_LOG_ERROR, "Volume name is not given " + "for the snapshot deletion"); + ret = -1; + goto out; + } + } else { + if (strcmp (words[cmdi], "-c")) { + gf_log ("", GF_LOG_ERROR, "volume name is not needed " + "for consistency group deletion"); + ret = -1; + goto out; + } + } + + /* Saving snap-name/cg-name in dict */ + if (name_opt_loc >= cmdi) { + /* Decide if it's a cg-name or a snap-name */ + if (is_cg) { + ret = dict_set_str (dict, "cgname", + (char *)words[name_opt_loc + 1]); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to save cg-name"); + goto out; + } + } else { + ret = dict_set_int64 (dict, "volcount", 1); + if (ret) { + gf_log ("", GF_LOG_ERROR, "failed to set " + "volcount"); + goto out; + } + ret = dict_set_str (dict, "volname1", + (char *)words[name_opt_loc - 1]); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to save volname"); + goto out; + } + ret = dict_set_str (dict, "snapname", + (char *)words[name_opt_loc + 1]); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to save snapname"); + goto out; + } + } + } + +out: + return ret; +} /* Syntax: * snapshot restore (-v | -c ) @@ -3391,95 +3482,129 @@ cli_cmd_snapshot_parse (const char **words, int wordcount, dict_t **options, goto out; } - /* Check which op is intended */ - if (strcmp (w, "create") == 0) { - /*syntax: - * snapshot create [-n ] - * [-d ] - */ - - /* In cases where the vol-name is not given - * parsing fails. volname cannot be an opword. - * and that is what this check verifies */ - w = str_getunamb (words[2], opwords); - if (w) - goto out; - + if (!strcmp (w, "create")) type = GF_SNAP_OPTION_TYPE_CREATE; - cmdi = 1; - - ret = cli_snap_create_parse (dict, words, wordcount, cmdi); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "create command parsing failed."); - goto out; - } - } else if (strcmp (w, "delete") == 0) { - gf_log ("", GF_LOG_ERROR, "Operation Not supported"); - goto out; - } else if (strcmp (w, "restore") == 0) { - /* Syntax: - * snapshot restore (-v | -c ) - */ + if (!strcmp (w, "list")) + type = GF_SNAP_OPTION_TYPE_LIST; + if (!strcmp (w, "delete")) + type = GF_SNAP_OPTION_TYPE_DELETE; + if (!strcmp (w, "config")) + type = GF_SNAP_OPTION_TYPE_CONFIG; + if (!strcmp (w, "restore")) type = GF_SNAP_OPTION_TYPE_RESTORE; - /* Start parsing from the first option after "restore" */ - cmdi = 2; - - ret = cli_snap_restore_parse (dict, words, wordcount, cmdi); - if (ret) { - gf_log ("cli", GF_LOG_ERROR, "Failed to parse " - "restore command"); - goto out; - } - } else if (strcmp (w, "start") == 0) { - gf_log ("", GF_LOG_ERROR, "Operation Not supported"); - goto out; - } else if (strcmp (w, "stop") == 0) { - gf_log ("", GF_LOG_ERROR, "Operation Not supported"); - goto out; - } else if (strcmp (w, "list") == 0) { - /* snapshot list [ | [-s ] - * | -c ] [-d] */ - /* check if arguments contains any Keyword */ - cmdi = 2; - for (i = cmdi ; i < wordcount ; i++) { - w = str_getunamb (words[i], opwords); - if (w) { - /*Checks if the operation is a valid operation*/ - cli_out ("Usage of Keyword in wrong place"); - gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); - goto out; - } - } + /* Check which op is intended */ + switch (type) { + case GF_SNAP_OPTION_TYPE_CREATE: + { + /*syntax: + snapshot create [-n ] + [-d ] + */ + + /* In cases where the vol-name is not given + * parsing fails. volname cannot be an opword. + * and that is what this check verifies */ + w = str_getunamb (words[2], opwords); + if (w) + goto out; + cmdi = 1; - type = GF_SNAP_OPTION_TYPE_LIST; + ret = cli_snap_create_parse (dict, words, + wordcount, cmdi); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "create command parsing failed."); + goto out; + } + break; + } + case GF_SNAP_OPTION_TYPE_LIST: + { + /* snapshot list [ | [-s ] + * | -c ] [-d] */ + /* check if arguments contains any Keyword */ + cmdi = 2; + for (i = cmdi ; i < wordcount ; i++) { + w = str_getunamb (words[i], opwords); + if (w) { + /*Checks if the operation is a valid + operation*/ + cli_out ("Usage of Keyword in wrong " + "place"); + gf_log ("", GF_LOG_ERROR, "Opword " + "Mismatch"); + goto out; + } + } - ret = cli_snap_list_parse (dict, words, - wordcount, cmdi); + ret = cli_snap_list_parse (dict, words, + wordcount, cmdi); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "list command parsing failed."); - goto out; - } - } else if (strcmp (w, "status") == 0) { - gf_log ("", GF_LOG_ERROR, "Operation Not supported"); - goto out; - } else if (strcmp (w, "config") == 0) { - /* snapshot config [snap_max_limit ] */ + if (ret) { + gf_log ("", GF_LOG_ERROR, + "list command parsing failed."); + goto out; + } + break; + } + case GF_SNAP_OPTION_TYPE_DELETE: + { + /*syntax: + snapshot remove [ -s | -c ] + */ + w = str_getunamb (words[2], opwords); + if (w) { + gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); + goto out; + } - type = GF_SNAP_OPTION_TYPE_CONFIG; + cmdi = 2; - ret = cli_snap_config_parse (words, wordcount, dict, state); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "config command parsing failed."); - goto out; - } - } else { - gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); - goto out; + ret = cli_snap_remove_parse (dict, words, + wordcount, cmdi); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "remove command parsing failed."); + goto out; + } + break; + } + case GF_SNAP_OPTION_TYPE_CONFIG: + { + /* snapshot config [snap_max_limit ] */ + ret = cli_snap_config_parse (words, wordcount, dict, + state); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "config command parsing failed."); + goto out; + } + break; + } + case GF_SNAP_OPTION_TYPE_RESTORE: + { + /* Syntax: + * snapshot restore (-v | + * -c ) + */ + + /* Start parsing from the first option after "restore" */ + cmdi = 2; + + ret = cli_snap_restore_parse (dict, words, wordcount, + cmdi); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to parse " + "restore command"); + goto out; + } + break; + } + default: + gf_log ("", GF_LOG_ERROR, "Opword Mismatch"); + goto out; + break; } ret = dict_set_int32 (dict, "type", type); diff --git a/cli/src/cli-cmd-snapshot.c b/cli/src/cli-cmd-snapshot.c index b3bc98abf..6aac4d29f 100644 --- a/cli/src/cli-cmd-snapshot.c +++ b/cli/src/cli-cmd-snapshot.c @@ -94,6 +94,10 @@ struct cli_cmd snapshot_cmds[] = { cli_cmd_snapshot_cbk, "Snapshot Config." }, + {"snapshot delete ( -s | -c )", + cli_cmd_snapshot_cbk, + "Snapshot Delete." + }, { NULL, NULL, NULL } }; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 830bd763f..1a90e192c 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -7838,6 +7838,63 @@ out : return ret; } +int32_t +cli_snapshot_remove_reply (gf_cli_rsp *rsp, dict_t *dict, call_frame_t *frame) +{ + int32_t ret = -1; + char *snap_name = NULL; + char *cg_name = NULL; + int64_t volcount = -1; + char *volname = NULL; + gf_boolean_t is_cg = _gf_false; + + GF_ASSERT (rsp); + GF_ASSERT (dict); + GF_ASSERT (frame); + + if (rsp->op_ret) { + cli_err("snapshot remove: failed: %s", + rsp->op_errstr ? rsp->op_errstr : + "Please check log file for details"); + ret = rsp->op_ret; + goto out; + } + + ret = dict_get_int64 (dict, "volcount", &volcount); + if (!ret) { + if (volcount == 1) { + ret = dict_get_str (dict, "volname1", &volname); + if (ret) + gf_log ("", GF_LOG_WARNING, "getting volume name" + " failed"); + } else + is_cg = _gf_true; + } + + if (is_cg) { + if (dict_get_str (dict, "cgname", + &cg_name) != 0) + cg_name = "???"; + + cli_out ("snapshot delete: %s: consistency " + "group removed successfully", + cg_name); + } else { + if (dict_get_str (dict, "snapname", + &snap_name) != 0) + snap_name = "???"; + + cli_out ("snapshot delete: %s: " + "snap removed successfully", + snap_name); + } + + ret = 0; + +out: + return ret; +} + int gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) @@ -8045,6 +8102,10 @@ gf_cli_snapshot_cbk (struct rpc_req *req, struct iovec *iov, } break; + case GF_SNAP_OPTION_TYPE_DELETE: + ret = cli_snapshot_remove_reply (&rsp, dict, frame); + break; + default: cli_err ("Unknown command executed"); ret = -1; diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c index b5859faaf..3e98e2fa2 100644 --- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c @@ -955,65 +955,6 @@ out: return ret; } -int -glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, - dict_t *rsp_dict) -{ - int snap_command = 0; - xlator_t *this = NULL; - int ret = -1; - - this = THIS; - - GF_ASSERT (this); - GF_ASSERT (dict); - GF_ASSERT (rsp_dict); //not sure if this is needed, verify. - - ret = dict_get_int32 (dict, "type", &snap_command); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " - "the snapshot command"); - goto out; - } - - switch (snap_command) { - case (GF_SNAP_OPTION_TYPE_CREATE): - ret = glusterd_snapshot_create_prevalidate (dict, op_errstr, - rsp_dict); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Snapshot create " - "pre-validation failed"); - goto out; - } - break; - - case (GF_SNAP_OPTION_TYPE_CONFIG): - ret = glusterd_snapshot_config_prevalidate (dict, op_errstr); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Snapshot config " - "pre-validation failed"); - goto out; - } - break; - - case GF_SNAP_OPTION_TYPE_RESTORE: - ret = glusterd_snapshot_restore_prevalidate (dict, op_errstr); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Snapshot restore " - "validation failed"); - goto out; - } - break; - default: - gf_log (this->name, GF_LOG_WARNING, "invalid snap command"); - goto out; - } - - ret = 0; -out: - return ret; -} - glusterd_snap_t* glusterd_new_snap_object() { @@ -2665,6 +2606,55 @@ out: return ret; } +int32_t +glusterd_snap_delete (glusterd_snap_t *snap) +{ + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!snap) { + gf_log (this->name, GF_LOG_WARNING, "snap object is NULL"); + goto out; + } + + GF_FREE (snap->description); + ret = glusterd_volinfo_delete (snap->snap_volume); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "deleting the snap volume" + "failed for the snap %s", snap->snap_name); + GF_FREE (snap); + ret = 0; + +out: + return ret; +} + +int32_t +glusterd_cg_delete (glusterd_snap_cg_t *cg) +{ + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!cg) { + gf_log (this->name, GF_LOG_WARNING, "consistency group is " + "NULL"); + goto out; + } + + GF_FREE (cg->description); + GF_FREE (cg); + ret = 0; + +out: + return ret; +} + /* this should be the last thing to be done. 1. Do op stage related checks such as whether volume is there or not etc 2. Do quorum checks. @@ -3260,113 +3250,733 @@ out: return snapname; } -/* name can be either the snapname if @volnames contains only one volume or - cg name if there are multiple volume names in volnames string -*/ - -int32_t -glusterd_snapshot_create_commit (dict_t *dict, char **op_errstr, - dict_t *rsp_dict) +/* This is a snapshot remove handler function. This function will be + * executed in the originator node. This function is responsible for + * calling mgmt v3 framework to do the actual remove on all the bricks + * + * @param req RPC request object + * @param op gluster operation + * @param dict dictionary containing snapshot remove request + * @param err_str In case of an err this string should be populated + * @param len length of err_str buffer + * + * @return Negative value on Failure and 0 in success + */ +int +glusterd_handle_snapshot_remove (rpcsvc_request_t *req, glusterd_op_t op, + dict_t *dict, char *err_str, size_t len) { - int ret = -1; - int i = 0; - int64_t volume_count = 0; - gf_boolean_t is_cg = _gf_false; - char *name = NULL; - char *volname = NULL; - char *tmp = NULL; - char volname_buf[PATH_MAX] = ""; - char snapvolidname[PATH_MAX] = ""; - xlator_t *this = NULL; - glusterd_volinfo_t *volinfo = NULL; - glusterd_snap_cg_t *cg = NULL; - glusterd_conf_t *priv = NULL; - uuid_t *cg_id = NULL; - uuid_t *snap_volid = NULL; - glusterd_snap_t *snap = NULL; - char err_str[PATH_MAX] = ""; + int ret = -1; + int64_t vol_count = 0; + char *volname = NULL; + char *snapname = NULL; + char *cgname = NULL; + glusterd_conf_t *conf = NULL; + glusterd_snap_cg_t *cg = NULL; + xlator_t *this = NULL; this = THIS; GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); + conf = this->private; - ret = dict_get_int64 (dict, "volcount", &volume_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get the volume count"); - goto out; - } + GF_ASSERT (conf); + GF_ASSERT (req); + GF_ASSERT (dict); + GF_ASSERT (err_str); - if (volume_count == 1) { - ret = dict_get_str (dict, "snap-name", &name); + /* If volume name is provided then volcount will be set */ + ret = dict_get_int64 (dict, "volcount", &vol_count); + if (ret) { + /* If volcount is not provided then cgname must be there */ + ret = dict_get_str (dict, "cgname", &cgname); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to fetch snap-name"); + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get neither volcount nor cgname"); goto out; } } else { - ret = dict_get_str (dict, "cg-name", &name); + /* TODO: Change the index to 0 when mgmt v3 code is fixed */ + ret = dict_get_str (dict, "volname1", &volname); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to fetch cg-name"); + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get volname"); + goto out; + } + ret = dict_get_str (dict, "snapname", &snapname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get snapname"); goto out; } } - ret = dict_get_bin (dict, "cg-id", (void **)&cg_id); - if (ret) - gf_log (this->name, GF_LOG_DEBUG, "Not a cg."); - else { - is_cg = _gf_true; - gf_log (this->name, GF_LOG_DEBUG, "cg-id = %s", uuid_utoa(*cg_id)); - } + if (NULL != cgname) { + cg = glusterd_find_snap_cg_by_name (conf, cgname); - if (volume_count > 1) { - cg = glusterd_new_snap_cg_object (volume_count); - if (!cg) { - gf_log (this->name, GF_LOG_ERROR, "cannot create the " - "consistency group %s", name); + if (NULL == cg) { + snprintf (err_str, len, "CG %s not found", cgname); + gf_log (this->name, GF_LOG_WARNING, "%s", err_str); + ret = -1; goto out; } - } - for (i = 1; i < volume_count + 1; i++) { - snprintf (volname_buf, sizeof (volname_buf), - "volname%d", i); - ret = dict_get_str (dict, volname_buf, - &volname); + LOCK (&cg->lock); + { + /* Get the volumes belong to CG */ + ret = glusterd_get_cg_volume_names_lk (dict, cg); + } + UNLOCK (&cg->lock); + if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get volume name"); + gf_log (this->name, GF_LOG_ERROR, "Failed to get " + "volume names of %s CG", cgname); goto out; } + } - ret = glusterd_volinfo_find (volname, &volinfo); + ret = glusterd_mgmt_v3_initiate_snap_phases (req, op, dict); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to initiate snap " + "phases"); + goto out; + } + + ret = 0; /* Success */ + +out: + return ret; +} + +int +glusterd_snapshot_remove_prevalidate (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int32_t ret = -1; + char *volname = NULL; + char *name = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + glusterd_snap_t *snap = NULL; + glusterd_snap_cg_t *cg = NULL; + char volname_buf[PATH_MAX] = {0, }; + glusterd_volinfo_t *volinfo = NULL; + char err_str[PATH_MAX] = {0, }; + int64_t volcount = 0; + int64_t i = 0; + int64_t j = 0; + gf_boolean_t volume_found = _gf_false; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + GF_ASSERT (op_errstr); + + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "input dict is NULL"); + goto out; + } + + ret = dict_get_int64 (dict, "volcount", &volcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting volcount failed"); + goto out; + } + + /* TODO: The policy for the snapshot create is not decided on + whether to start the snap volume upon the execution of the + snapshot create command. Once the policy is decided, check + here whether the volume is in use before delete command is + executed. (May be a force option to delete forcefully even + when the snap volume is in use.) + */ + + if (volcount > 1) { + ret = dict_get_str (dict, "cgname", &name); if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get the volinfo for " - "the volume %s", volname); + gf_log (this->name, GF_LOG_ERROR, "getting the cg name" + " failed"); goto out; } - - tmp = generate_snapname (volname, name, is_cg); - if (!tmp) { - gf_log (this->name, - GF_LOG_ERROR, "strdup " - "failed (%s)", name); + cg = glusterd_find_snap_cg_by_name (conf, name); + if (!cg) { + snprintf (err_str, sizeof (err_str), "consistency group" + "%s is not found", name); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + *op_errstr = gf_strdup (err_str); goto out; } + GF_ASSERT (volcount == cg->volume_count); - list_for_each_entry (snap, &volinfo->snaps, snap_list) { - if (!strcmp (snap->snap_name, tmp)) { - snprintf (err_str, sizeof (err_str), "snap " - "with name %s already exists", tmp); - gf_log (this->name, GF_LOG_ERROR, "%s", - err_str); - ret = -1; - *op_errstr = gf_strdup (err_str); + for (i = 0; i < volcount; i++) { + volume_found = _gf_false; + snprintf (volname_buf, sizeof (volname_buf), + "volname%ld", i+1); + ret = dict_get_str (dict, volname_buf, &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "volume name " + "is notgiven"); goto out; } - } + for (j = 0; j < volcount; j++) { + volinfo = cg->volumes[j]; + if (!strcmp (volinfo->volname, volname)) { + volume_found = _gf_true; + break; + } + } + if (!volume_found) { + gf_log (this->name, GF_LOG_ERROR, "volume %s" + " is not found in the consistency " + "group %s", volname, name); + goto out; + } + } + } else { + snprintf (volname_buf, sizeof (volname_buf), "volname1"); + ret = dict_get_str (dict, volname_buf, &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "volume name is not " + "given"); + goto out; + } + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get the volinfo for " + "the volume %s", volname); + goto out; + } + ret = dict_get_str (dict, "snapname", &name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting snap name " + "failed (volume: %s)", volname); + goto out; + } + snap = glusterd_find_snap_by_name (volinfo, name); + if (!snap) { + ret = -1; + snprintf (err_str, sizeof (err_str), "snap %s is not " + "found", name); + gf_log (this->name, GF_LOG_ERROR, "%s, (volume: %s)", + err_str, volinfo->volname); + *op_errstr = gf_strdup (err_str); + goto out; + } + } + + ret = 0; +out: + return ret; +} + +int +glusterd_remove_snap (glusterd_brickinfo_t *brickinfo, const char *mount_pt, + const char *volname, const char *snapname, + const char *snap_device) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + runner_t runner = {0,}; + char msg[1024] = {0, }; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + if (!brickinfo) { + gf_log (this->name, GF_LOG_ERROR, "brickinfo NULL"); + goto out; + } + + GF_ASSERT (mount_pt); + GF_ASSERT (volname); + GF_ASSERT (snapname); + GF_ASSERT (snap_device); + + /* sleep for some time so that the glusterfsd process associated + with the snap lvm does not have any reference to the snap and + has been stopped completely + TODO: find the issue because of which umount fails and fix it. + */ + //usleep (24007); + + //ret = umount2 (mount_pt, MNT_FORCE); + runinit (&runner); + snprintf (msg, sizeof (msg), "umount the snapshot mounted path %s", + mount_pt); + runner_add_args (&runner, "umount", mount_pt, NULL); + runner_log (&runner, "", GF_LOG_DEBUG, msg); + + /* We need not do synclock_unlock => runner_run => synclock_lock here. + Because it is needed if we are running a glusterfs process in + runner_run, so that when the glusterfs process started wants to + communicate to glusterd, glusterd wont be able to respond if it + has held the big lock. So we do unlock, run glusterfs process + (thus communicate to glusterd), lock. But since this is not a + glusterfs command that is being run, unlocking and then relocking + is not needed. + */ + ret = runner_run (&runner); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "unmounting the " + "path %s (brick: %s) failed (%s)", mount_pt, + brickinfo->path, strerror (errno)); + goto out; + } + + runinit (&runner); + snprintf (msg, sizeof(msg), "remove snapshot of the brick %s:%s, " + "device: %s", brickinfo->hostname, brickinfo->path, + snap_device); + runner_add_args (&runner, "/sbin/lvremove", "-f", snap_device, NULL); + runner_log (&runner, "", GF_LOG_DEBUG, msg); + + ret = runner_run (&runner); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing snapshot of the " + "brick (%s:%s) of device %s failed", + brickinfo->hostname, brickinfo->path, snap_device); + goto out; + } + +out: + return ret; +} + +int32_t +glusterd_brick_snapshot_remove (glusterd_volinfo_t *snap_volinfo, + glusterd_volinfo_t *actual_volinfo, char *name) +{ + char *mnt_pt = NULL; + struct mntent *entry = NULL; + int32_t ret = -1; + glusterd_brickinfo_t *brickinfo = NULL; + xlator_t *this = NULL; + FILE *mtab = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!snap_volinfo) { + gf_log (this->name, GF_LOG_ERROR, "snap volinfo is NULL"); + goto out; + } + + if (!actual_volinfo) { + gf_log (this->name, GF_LOG_ERROR, "volinfo for the volume " + "is NULL"); + goto out; + } + + if (!name) { + gf_log (this->name, GF_LOG_ERROR, "snapname is NULL " + "(volume: %s)", actual_volinfo->volname); + goto out; + } + + list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) { + if (uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + ret = glusterd_get_brick_root (brickinfo->path, &mnt_pt); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "getting the root " + "of the brick for snap volume %s faile", name); + goto out; + } + + entry = glusterd_get_mnt_entry_info (mnt_pt, mtab); + if (!entry) { + gf_log (this->name, GF_LOG_WARNING, "getting the mount" + " entry for the brick %s:%s of the snap %s " + "(volume: %s) failed", brickinfo->hostname, + brickinfo->path, name, actual_volinfo->volname); + ret = -1; + goto out; + } + ret = glusterd_remove_snap (brickinfo, mnt_pt, + actual_volinfo->volname, + name, entry->mnt_fsname); + if (mtab) + endmntent (mtab); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "remove the snapshot %s (%s)", + brickinfo->path, entry->mnt_fsname); + goto out; + } + } + + ret = 0; + +out: + return ret; +} + +int32_t +glusterd_do_snap_remove (glusterd_volinfo_t *volinfo, char *name) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + glusterd_snap_t *snap = NULL; + glusterd_volinfo_t *snap_volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + if (!volinfo) { + gf_log (this->name, GF_LOG_ERROR, "volinfo NULL"); + goto out; + } + + if (!name) { + gf_log (this->name, GF_LOG_ERROR, "name is NULL (volume: %s)", + volinfo->volname); + goto out; + } + + snap = glusterd_find_snap_by_name (volinfo, name); + if (!snap) { + gf_log (this->name, GF_LOG_ERROR, "could not find " + "the snap object by the name %s", + name); + goto out; + } else { + gf_log (this->name, GF_LOG_DEBUG, "found the snap %s " + "(volume: %s)", name, volinfo->volname); + } + + snap_volinfo = snap->snap_volume; + GF_ASSERT (snap_volinfo); + list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) { + if (uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + /* TODO: The policy for the snapshot create is not + decided on whether to start the snap volume upon + the execution of the snapshot create command. Once + the policy is decided, check here whether the volume + is in use before delete command is executed. + (May be a force option to delete forcefully even + when the snap volume is in use.) + */ + ret = glusterd_snap_brick_stop (volinfo, snap_volinfo, + brickinfo, + _gf_false); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "stopping " + "the brick %s:%s for the snap %s " + "(volume: %s) failed", + brickinfo->hostname, + brickinfo->path, snap_volinfo->volname, + volinfo->volname); + //goto out; + } + } + ret = glusterd_brick_snapshot_remove (snap_volinfo, volinfo, + name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing the bricks" + " snapshots for the snap %s (volume: %s) " + "failed", name, volinfo->volname); + goto out; + } + + ret = glusterd_store_delete_volume (volinfo, snap->snap_volume); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing the snap " + "store for the snap %s (volume %s) failed", + snap->snap_name, volinfo->volname); + goto out; + } + + snap = glusterd_remove_snap_by_name (volinfo, snap->snap_name); + GF_ASSERT (snap); //snap cannot be NULL; + glusterd_snap_delete (snap); //deletes in memory snap object + + ret = glusterd_store_perform_snap_list_store (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "doing the snap " + "store for the volume %s failed", + volinfo->volname); + goto out; + } + + ret = 0; +out: + return ret; +} + +char * +glusterd_get_snap_from_cg (glusterd_volinfo_t *volinfo, glusterd_snap_cg_t *cg) +{ + char *snap_name = NULL; + glusterd_snap_t *tmp_snap = NULL; + glusterd_snap_t *snap = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!volinfo) { + gf_log (this->name, GF_LOG_WARNING, "volinfo NULL"); + goto out; + } + + if (!cg) { + gf_log (this->name, GF_LOG_WARNING, "consistency group NULL"); + goto out; + } + + list_for_each_entry (tmp_snap, &volinfo->snaps, snap_list) { + if ((!uuid_is_null (tmp_snap->cg_id)) && + (uuid_compare (tmp_snap->cg_id, cg->cg_id) == 0)) { + snap = tmp_snap; + break; + } + } + + if (snap) + snap_name = gf_strdup (snap->snap_name); + +out: + return snap_name; +} + +int32_t +glusterd_snapshot_remove_commit (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int32_t ret = -1; + char *cg_name = NULL; + char *name = NULL; + glusterd_snap_cg_t *cg = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + int64_t volcount = -1; + char volname_buf[PATH_MAX] = {0, }; + int i = 0; + gf_boolean_t free_name = _gf_false; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + if (!dict || !op_errstr) { + gf_log (this->name, GF_LOG_ERROR, "input parameters NULL"); + goto out; + } + + ret = dict_get_int64 (dict, "volcount", &volcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "volume count not given"); + goto out; + } + + if (volcount > 1) { + ret = dict_get_str (dict, "cgname", &cg_name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting the cg name" + " failed"); + goto out; + } + cg = glusterd_find_snap_cg_by_name (conf, cg_name); + if (!cg) { + gf_log (this->name, GF_LOG_ERROR, "consistency group " + "%s not found", cg_name); + goto out; + } + GF_ASSERT (volcount == cg->volume_count); + } + + for (i = 0; i < volcount; i++) { + snprintf (volname_buf, sizeof (volname_buf), "volname%d", i+1); + ret = dict_get_str (dict, volname_buf, &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting volume name" + "failed"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting the volinfo" + " failed for the volume %s", volname); + goto out; + } + ret = dict_get_str (dict, "snapname", &name); + if (ret && volcount == 1) { + gf_log (this->name, GF_LOG_ERROR, "getting the snap " + "name failed (volume: %s)", volinfo->volname); + goto out; + } + + if (!name) { + name = glusterd_get_snap_from_cg (volinfo, cg); + if (!name) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the snap name " + "(volname: %s, cg name: %s)", + volinfo->volname, cg->cg_name); + goto out; + } + free_name = _gf_true; + } + + ret = glusterd_do_snap_remove (volinfo, name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "removing the %s %s failed", + (volinfo)?"snap":"cg", name); + goto out; + } + if (free_name) + GF_FREE (name); + name = NULL; + } + + if (volcount > 1) { + ret = glusterd_store_delete_snap_cg (cg); + /* TODO: Handle the errors of deleting store handle of cg. + For now, the error is ignored and we proceed with the + deletion of the in memory cg object. + */ + if (ret) + gf_log (this->name, GF_LOG_WARNING, "removing the " + "store handle for the consistency group %s " + "failed", cg->cg_name); + cg = glusterd_remove_snap_cg_by_name (conf, cg_name); + ret = glusterd_cg_delete (cg); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "removing the cg " + "object failed"); + goto out; + } + } + + ret = 0; +out: + if (free_name) + GF_FREE (name); + return ret; +} + +/* name can be either the snapname if @volnames contains only one volume or + cg name if there are multiple volume names in volnames string +*/ + +int32_t +glusterd_snapshot_create_commit (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int ret = -1; + int i = 0; + int64_t volume_count = 0; + gf_boolean_t is_cg = _gf_false; + char *name = NULL; + char *volname = NULL; + char *tmp = NULL; + char volname_buf[PATH_MAX] = ""; + char snapvolidname[PATH_MAX] = ""; + xlator_t *this = NULL; + glusterd_volinfo_t *volinfo = NULL; + glusterd_snap_cg_t *cg = NULL; + glusterd_conf_t *priv = NULL; + uuid_t *cg_id = NULL; + uuid_t *snap_volid = NULL; + glusterd_snap_t *snap = NULL; + char err_str[PATH_MAX] = ""; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + ret = dict_get_int64 (dict, "volcount", &volume_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the volume count"); + goto out; + } + + if (volume_count == 1) { + ret = dict_get_str (dict, "snap-name", &name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to fetch snap-name"); + goto out; + } + } else { + ret = dict_get_str (dict, "cg-name", &name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to fetch cg-name"); + goto out; + } + } + + ret = dict_get_bin (dict, "cg-id", (void **)&cg_id); + if (ret) + gf_log (this->name, GF_LOG_DEBUG, "Not a cg."); + else { + is_cg = _gf_true; + gf_log (this->name, GF_LOG_DEBUG, "cg-id = %s", uuid_utoa(*cg_id)); + } + + if (volume_count > 1) { + cg = glusterd_new_snap_cg_object (volume_count); + if (!cg) { + gf_log (this->name, GF_LOG_ERROR, "cannot create the " + "consistency group %s", name); + goto out; + } + } + + for (i = 1; i < volume_count + 1; i++) { + snprintf (volname_buf, sizeof (volname_buf), + "volname%d", i); + ret = dict_get_str (dict, volname_buf, + &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get volume name"); + goto out; + } + + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get the volinfo for " + "the volume %s", volname); + goto out; + } + + tmp = generate_snapname (volname, name, is_cg); + if (!tmp) { + gf_log (this->name, + GF_LOG_ERROR, "strdup " + "failed (%s)", name); + goto out; + } + + list_for_each_entry (snap, &volinfo->snaps, snap_list) { + if (!strcmp (snap->snap_name, tmp)) { + snprintf (err_str, sizeof (err_str), "snap " + "with name %s already exists", tmp); + gf_log (this->name, GF_LOG_ERROR, "%s", + err_str); + ret = -1; + *op_errstr = gf_strdup (err_str); + goto out; + } + } memset (snapvolidname, '\0', sizeof(snapvolidname)); ret = snprintf (snapvolidname, sizeof(snapvolidname) - 1, @@ -3615,6 +4225,16 @@ glusterd_snapshot (dict_t *dict, char **op_errstr, dict_t *rsp_dict) rsp_dict); break; + case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_snapshot_remove_commit (dict, op_errstr, + rsp_dict); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "delete snapshot"); + goto out; + } + break; + case GF_SNAP_OPTION_TYPE_RESTORE: ret = glusterd_snapshot_restore (dict, op_errstr); if (ret) { @@ -3700,6 +4320,74 @@ out: return ret; } +int +glusterd_snapshot_prevalidate (dict_t *dict, char **op_errstr, + dict_t *rsp_dict) +{ + int snap_command = 0; + xlator_t *this = NULL; + int ret = -1; + + this = THIS; + + GF_ASSERT (this); + GF_ASSERT (dict); + GF_ASSERT (rsp_dict); //not sure if this is needed, verify. + + ret = dict_get_int32 (dict, "type", &snap_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " + "the snapshot command"); + goto out; + } + + switch (snap_command) { + case (GF_SNAP_OPTION_TYPE_CREATE): + ret = glusterd_snapshot_create_prevalidate (dict, op_errstr, + rsp_dict); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot create " + "pre-validation failed"); + goto out; + } + break; + + case (GF_SNAP_OPTION_TYPE_CONFIG): + ret = glusterd_snapshot_config_prevalidate (dict, op_errstr); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot config " + "pre-validation failed"); + goto out; + } + break; + + case GF_SNAP_OPTION_TYPE_RESTORE: + ret = glusterd_snapshot_restore_prevalidate (dict, op_errstr); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot restore " + "validation failed"); + goto out; + } + break; + case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_snapshot_remove_prevalidate (dict, op_errstr, + rsp_dict); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot remove " + "validation failed"); + goto out; + } + break; + default: + gf_log (this->name, GF_LOG_WARNING, "invalid snap command"); + goto out; + } + + ret = 0; +out: + return ret; +} + int glusterd_handle_snapshot_fn (rpcsvc_request_t *req) { @@ -3797,6 +4485,14 @@ glusterd_handle_snapshot_fn (rpcsvc_request_t *req) ret = glusterd_mgmt_v3_initiate_all_phases (req, cli_op, dict); break; case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_handle_snapshot_remove (req, cli_op, dict, + err_str, + sizeof (err_str)); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot delete " + "failed: %s", err_str); + } + break; case GF_SNAP_OPTION_TYPE_START: case GF_SNAP_OPTION_TYPE_STOP: case GF_SNAP_OPTION_TYPE_STATUS: diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 9492baf3a..e9df28b8f 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -1687,6 +1687,52 @@ glusterd_brick_unlink_socket_file (glusterd_volinfo_t *volinfo, return ret; } +int32_t +glusterd_snap_brick_unlink_socket_file (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo) +{ + char path[PATH_MAX] = {0,}; + char socketpath[PATH_MAX] = {0}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + int ret = 0; + char sock_filepath[PATH_MAX] = {0, }; + int expected_file_len = 0; + char export_path[PATH_MAX] = {0,}; + + GF_ASSERT (volinfo); + GF_ASSERT (snap_volinfo); + GF_ASSERT (brickinfo); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + GLUSTERD_GET_SNAP_DIR (path, volinfo, snap_volinfo->volname, priv); + + glusterd_set_socket_filepath (sock_filepath, socketpath, sizeof (socketpath)); + + expected_file_len = strlen (GLUSTERD_SOCK_DIR) + strlen ("/") + + MD5_DIGEST_LENGTH*2 + strlen (".socket") + 1; + GF_ASSERT (sizeof (socketpath) >= expected_file_len); + + GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, export_path); + snprintf (sock_filepath, PATH_MAX, "%s/run/%s-%s", + path, brickinfo->hostname, export_path); + + ret = unlink (socketpath); + if (ret && (ENOENT == errno)) { + ret = 0; + } else { + gf_log (this->name, GF_LOG_ERROR, "Failed to remove %s" + " error: %s", socketpath, strerror (errno)); + } + + return ret; +} + int32_t glusterd_brick_disconnect (glusterd_brickinfo_t *brickinfo) { @@ -1748,6 +1794,49 @@ glusterd_volume_stop_glusterfs (glusterd_volinfo_t *volinfo, return ret; } +int32_t +glusterd_snap_volume_stop_glusterfs (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo, + gf_boolean_t del_brick) +{ + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + char pidfile[PATH_MAX] = {0,}; + int ret = 0; + + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + GF_ASSERT (snap_volinfo); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + if (del_brick) + list_del_init (&brickinfo->brick_list); + + if (GLUSTERD_STATUS_STARTED == volinfo->status) { + (void) glusterd_brick_disconnect (brickinfo); + GLUSTERD_GET_SNAP_BRICK_PIDFILE (pidfile, volinfo, + snap_volinfo->volname, + brickinfo, priv); + ret = glusterd_service_stop ("brick", pidfile, SIGTERM, _gf_false); + if (ret == 0) { + glusterd_set_brick_status (brickinfo, GF_BRICK_STOPPED); + (void) glusterd_snap_brick_unlink_socket_file (volinfo, + snap_volinfo, + brickinfo); + } + } + + if (del_brick) + glusterd_delete_snap_brick (volinfo, snap_volinfo, brickinfo); + + return ret; +} + int32_t glusterd_peer_hostname_new (char *hostname, glusterd_peer_hostname_t **name) { @@ -5357,6 +5446,60 @@ out: return ret; } +int +glusterd_snap_brick_stop (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo, + gf_boolean_t del_brick) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + if ((!brickinfo) || (!volinfo) || !snap_volinfo) { + gf_log (this->name, GF_LOG_ERROR, "input parameters NULL"); + goto out; + } + + if (uuid_is_null (brickinfo->uuid)) { + ret = glusterd_resolve_brick (brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK, + brickinfo->hostname, brickinfo->path); + goto out; + } + } + + if (uuid_compare (brickinfo->uuid, MY_UUID)) { + ret = 0; + if (del_brick) + glusterd_delete_snap_brick (volinfo, snap_volinfo, + brickinfo); + goto out; + } + + gf_log (this->name, GF_LOG_DEBUG, "About to stop glusterfs" + " for brick %s:%s", brickinfo->hostname, + brickinfo->path); + ret = glusterd_snap_volume_stop_glusterfs (volinfo, snap_volinfo, + brickinfo, del_brick); + if (ret) { + gf_log (this->name, GF_LOG_CRITICAL, "Unable to stop" + " brick: %s:%s", brickinfo->hostname, + brickinfo->path); + goto out; + } + +out: + gf_log (this->name, GF_LOG_TRACE, "returning %d ", ret); + return ret; +} + int glusterd_is_defrag_on (glusterd_volinfo_t *volinfo) { @@ -6005,6 +6148,49 @@ glusterd_delete_brick (glusterd_volinfo_t* volinfo, return ret; } +int32_t +glusterd_delete_snap_brick (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo) +{ + int ret = 0; + char voldir[PATH_MAX] = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + GF_ASSERT (volinfo); + GF_ASSERT (snap_volinfo); + GF_ASSERT (brickinfo); + + GLUSTERD_GET_SNAP_DIR(voldir, volinfo, snap_volinfo->volname, priv); + + ret = glusterd_delete_snap_volfile (volinfo, snap_volinfo, brickinfo); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "failed to delete the " + "volfile for the brick (%s:%s), snap: %s volume: %s", + brickinfo->hostname, brickinfo->path, + snap_volinfo->volname, volinfo->volname); + ret = glusterd_store_delete_brick (brickinfo, voldir); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "failed to delete the " + "store handle of brick (%s:%s), snap: %s volume: %s", + brickinfo->hostname, brickinfo->path, + snap_volinfo->volname, volinfo->volname); + ret = glusterd_brickinfo_delete (brickinfo); + if (ret) + gf_log (this->name, GF_LOG_WARNING, "failed to delete the " + "brickinfo (%s:%s), snap: %s volume: %s", + brickinfo->hostname, brickinfo->path, + snap_volinfo->volname, volinfo->volname); + snap_volinfo->brick_count--; + return ret; +} + int32_t glusterd_delete_all_bricks (glusterd_volinfo_t* volinfo) { diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index ca3c620aa..4c98559c9 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -292,6 +292,11 @@ glusterd_snap_brick_start (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo, gf_boolean_t wait); int +glusterd_snap_brick_stop (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo, + gf_boolean_t del_brick); +int glusterd_is_defrag_on (glusterd_volinfo_t *volinfo); int32_t @@ -374,6 +379,10 @@ int32_t glusterd_delete_brick (glusterd_volinfo_t* volinfo, glusterd_brickinfo_t *brickinfo); int32_t +glusterd_delete_snap_brick (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo); +int32_t glusterd_delete_all_bricks (glusterd_volinfo_t* volinfo); int glusterd_spawn_daemons (void *opaque); diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 50beb23f7..1bc0db6ce 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -3703,6 +3703,39 @@ glusterd_delete_volfile (glusterd_volinfo_t *volinfo, return ret; } +int +glusterd_delete_snap_volfile (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo) +{ + int ret = 0; + char filename[PATH_MAX] = {0,}; + char brick[PATH_MAX] = {0, }; + char path[PATH_MAX] = {0, }; + glusterd_conf_t *priv = NULL; + + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + GF_ASSERT (snap_volinfo); + + priv = THIS->private; + GF_ASSERT (priv); + + GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, brick); + GLUSTERD_GET_SNAP_DIR (path, volinfo, snap_volinfo->volname, priv); + + snprintf (filename, PATH_MAX, "%s/%s.%s.%s.vol", + path, snap_volinfo->volname, + brickinfo->hostname, + brick); + + ret = unlink (filename); + if (ret) + gf_log ("glusterd", GF_LOG_ERROR, "failed to delete file: %s, " + "reason: %s", filename, strerror (errno)); + return ret; +} + int validate_shdopts (glusterd_volinfo_t *volinfo, dict_t *val_dict, diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h index dc334ca8d..2b22f5226 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.h +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h @@ -124,6 +124,10 @@ int glusterd_create_shd_volfile (); int glusterd_delete_volfile (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo); +int +glusterd_delete_snap_volfile (glusterd_volinfo_t *volinfo, + glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo); int glusterd_volinfo_get (glusterd_volinfo_t *volinfo, char *key, char **value); int glusterd_volinfo_get_boolean (glusterd_volinfo_t *volinfo, char *key); -- cgit