summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaghavendra Bhat <raghavendra@redhat.com>2013-11-29 12:29:38 +0530
committerRaghavendra Bhat <raghavendra@redhat.com>2013-12-12 14:58:02 +0530
commit005b445d684f30e8611c9b2a374cdc798a6cdcbb (patch)
treed5a2f1893179e3b789aac58beed0e2495cee568f
parent112691a0d5a539b71c642228e197764248174f5d (diff)
cli/glusterd: implement the snap and cg delete functionalities
Change-Id: Icdb66c89acdd043d0d6368c48ce2e01b1a40966f Signed-off-by: Raghavendra Bhat <raghavendra@redhat.com>
-rw-r--r--cli/src/cli-cmd-parser.c287
-rw-r--r--cli/src/cli-cmd-snapshot.c4
-rw-r--r--cli/src/cli-rpc-ops.c61
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c814
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.c186
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-utils.h9
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c33
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.h4
8 files changed, 1258 insertions, 140 deletions
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index 4bbaa49..d1afa72 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 (<volname> -s <snapname> | -c <cgname>)"
+*/
+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 <volname> <snap-name> | -c <cg-name> )
@@ -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 <volnames> [-n <snap-name/cg-name>]
- * [-d <description>]
- */
-
- /* 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 <volname> <snap-name> | -c <cg-name> )
- */
+ 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 [<volnames> | <volname> [-s <snapname>]
- * | -c <cgname>] [-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 <volnames> [-n <snap-name/cg-name>]
+ [-d <description>]
+ */
+
+ /* 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 [<volnames> | <volname> [-s <snapname>]
+ * | -c <cgname>] [-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 <volname | all> [snap_max_limit <count>] */
+ if (ret) {
+ gf_log ("", GF_LOG_ERROR,
+ "list command parsing failed.");
+ goto out;
+ }
+ break;
+ }
+ case GF_SNAP_OPTION_TYPE_DELETE:
+ {
+ /*syntax:
+ snapshot remove [<volname> -s <snap-name> | -c <cg-name>]
+ */
+ 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 <volname | all> [snap_max_limit <count>] */
+ 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 <volname> <snap-name> |
+ * -c <cg-name> )
+ */
+
+ /* 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 b3bc98a..6aac4d2 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 (<volname> -s <snapname> | -c <cgname>)",
+ 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 830bd76..1a90e19 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 b5859fa..3e98e2f 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,6 +3250,626 @@ out:
return snapname;
}
+/* 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;
+ 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);
+ conf = this->private;
+
+ GF_ASSERT (conf);
+ GF_ASSERT (req);
+ GF_ASSERT (dict);
+ GF_ASSERT (err_str);
+
+ /* 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, "Failed to "
+ "get neither volcount nor cgname");
+ goto out;
+ }
+ } else {
+ /* 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, "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;
+ }
+ }
+
+ if (NULL != cgname) {
+ cg = glusterd_find_snap_cg_by_name (conf, cgname);
+
+ 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;
+ }
+
+ 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 names of %s CG", cgname);
+ goto out;
+ }
+ }
+
+ 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, "getting the cg name"
+ " failed");
+ goto out;
+ }
+ 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);
+
+ 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
*/
@@ -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) {
@@ -3701,6 +4321,74 @@ out:
}
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)
{
int32_t ret = 0;
@@ -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 9492baf..e9df28b 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -1688,6 +1688,52 @@ glusterd_brick_unlink_socket_file (glusterd_volinfo_t *volinfo,
}
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)
{
rpc_clnt_t *rpc = NULL;
@@ -1749,6 +1795,49 @@ glusterd_volume_stop_glusterfs (glusterd_volinfo_t *volinfo,
}
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)
{
glusterd_peer_hostname_t *peer_hostname = NULL;
@@ -5358,6 +5447,60 @@ out:
}
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)
{
return (volinfo->rebal.defrag != NULL);
@@ -6006,6 +6149,49 @@ glusterd_delete_brick (glusterd_volinfo_t* volinfo,
}
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)
{
int ret = 0;
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index ca3c620..4c98559 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 50beb23..1bc0db6 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
@@ -3704,6 +3704,39 @@ glusterd_delete_volfile (glusterd_volinfo_t *volinfo,
}
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,
char **op_errstr)
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h
index dc334ca..2b22f52 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);