summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajesh Joseph <rjoseph@redhat.com>2013-10-15 17:10:52 +0530
committershishir gowda <sgowda@redhat.com>2013-11-15 12:38:59 +0530
commitd15ad38e8623f510fb1e121a8ff0d845a99238e4 (patch)
tree797ddd93686670e4241584d2f0f978405037d927
parent6726c1617daeb783053a15d12189a64c27343f8c (diff)
mgmt/glusterd: Snapshot list support
Handles snapshot list command issued by cli. Details of all the snapshots will be sent back to the caller in required format. Change-Id: I01e512290548007c06e90b40a59cdde048fab954 Signed-off-by: Rajesh Joseph <rjoseph@redhat.com>
-rw-r--r--rpc/xdr/src/cli1-xdr.c11
-rw-r--r--rpc/xdr/src/cli1-xdr.h9
-rw-r--r--rpc/xdr/src/cli1-xdr.x7
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-snapshot.c1023
-rw-r--r--xlators/mgmt/glusterd/src/glusterd.h1
5 files changed, 1032 insertions, 19 deletions
diff --git a/rpc/xdr/src/cli1-xdr.c b/rpc/xdr/src/cli1-xdr.c
index 7d85b43..f0f08d3 100644
--- a/rpc/xdr/src/cli1-xdr.c
+++ b/rpc/xdr/src/cli1-xdr.c
@@ -179,6 +179,17 @@ xdr_gf_cli_status_type (XDR *xdrs, gf_cli_status_type *objp)
}
bool_t
+xdr_gf1_cli_snapshot (XDR *xdrs, gf1_cli_snapshot *objp)
+{
+ register int32_t *buf;
+ buf = NULL;
+
+ if (!xdr_enum (xdrs, (enum_t *) objp))
+ return FALSE;
+ return TRUE;
+}
+
+bool_t
xdr_gf_cli_req (XDR *xdrs, gf_cli_req *objp)
{
register int32_t *buf;
diff --git a/rpc/xdr/src/cli1-xdr.h b/rpc/xdr/src/cli1-xdr.h
index d418fab..bdc76b6 100644
--- a/rpc/xdr/src/cli1-xdr.h
+++ b/rpc/xdr/src/cli1-xdr.h
@@ -169,6 +169,13 @@ enum gf_cli_status_type {
};
typedef enum gf_cli_status_type gf_cli_status_type;
+enum gf1_cli_snapshot {
+ GF_SNAP_OPTION_TYPE_NONE = 0,
+ GF_SNAP_OPTION_TYPE_CREATE = 1,
+ GF_SNAP_OPTION_TYPE_LIST = 2,
+};
+typedef enum gf1_cli_snapshot gf1_cli_snapshot;
+
struct gf_cli_req {
struct {
u_int dict_len;
@@ -280,6 +287,7 @@ extern bool_t xdr_gf1_cli_gsync_set (XDR *, gf1_cli_gsync_set*);
extern bool_t xdr_gf1_cli_stats_op (XDR *, gf1_cli_stats_op*);
extern bool_t xdr_gf1_cli_top_op (XDR *, gf1_cli_top_op*);
extern bool_t xdr_gf_cli_status_type (XDR *, gf_cli_status_type*);
+extern bool_t xdr_gf1_cli_snapshot (XDR *, gf1_cli_snapshot*);
extern bool_t xdr_gf_cli_req (XDR *, gf_cli_req*);
extern bool_t xdr_gf_cli_rsp (XDR *, gf_cli_rsp*);
extern bool_t xdr_gf1_cli_peer_list_req (XDR *, gf1_cli_peer_list_req*);
@@ -308,6 +316,7 @@ extern bool_t xdr_gf1_cli_gsync_set ();
extern bool_t xdr_gf1_cli_stats_op ();
extern bool_t xdr_gf1_cli_top_op ();
extern bool_t xdr_gf_cli_status_type ();
+extern bool_t xdr_gf1_cli_snapshot ();
extern bool_t xdr_gf_cli_req ();
extern bool_t xdr_gf_cli_rsp ();
extern bool_t xdr_gf1_cli_peer_list_req ();
diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x
index cc7ca8e..b8dff56 100644
--- a/rpc/xdr/src/cli1-xdr.x
+++ b/rpc/xdr/src/cli1-xdr.x
@@ -122,6 +122,13 @@ enum gf_cli_status_type {
GF_CLI_STATUS_SHD = 0x1000 /*1000000000000*/
};
+/* Identifiers for snapshot clis */
+enum gf1_cli_snapshot {
+ GF_SNAP_OPTION_TYPE_NONE,
+ GF_SNAP_OPTION_TYPE_CREATE,
+ GF_SNAP_OPTION_TYPE_LIST
+};
+
struct gf_cli_req {
opaque dict<>;
} ;
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
index 1c0ea08..1c1e28a 100644
--- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c
+++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c
@@ -1,5 +1,5 @@
/*
- Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com>
+ Copyright (c) 2013 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
@@ -338,6 +338,1002 @@ out:
return entry;
}
+int32_t
+glusterd_delete_snap_volume (glusterd_volinfo_t *volinfo,
+ glusterd_volinfo_t *snapinfo)
+{
+ int ret = -1;
+
+ GF_ASSERT (volinfo);
+
+ ret = glusterd_store_delete_volume (volinfo, snapinfo);
+
+ if (ret)
+ goto out;
+
+ ret = glusterd_volinfo_delete (snapinfo);
+out:
+ gf_log (THIS->name, GF_LOG_DEBUG, "returning %d", ret);
+ return ret;
+}
+
+/* This function will retrieve the details of a single snap
+ * and then serialize them to dictionary (dict)
+ * This function is called under snap lock
+ *
+ * @param dict dictionary where response should be serialized
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param entry Snap object
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_get_snapdetail_lk (dict_t *dict, char *keyprefix,
+ glusterd_snap_t *entry,
+ int8_t detail)
+{
+ int ret = -1; /* Failure */
+ const int maxstrlen = 256;
+ char *value = NULL;
+ char *timestr = NULL;
+ struct tm *tmptr = NULL;
+ xlator_t *this = NULL;
+ char key[maxstrlen];
+
+ this = THIS;
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (entry);
+
+ /* Snap Name */
+ value = gf_strdup (entry->snap_name);
+ if (NULL == value) {
+ goto out;
+ }
+
+ snprintf (key, sizeof (key), "%s.snap-name", keyprefix);
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap name in dictionary");
+ goto out;
+ }
+
+ /* Snap ID */
+ value = gf_strdup (uuid_utoa (entry->snap_id));
+ if (NULL == value) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.snap-id", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap id in dictionary");
+ goto out;
+ }
+
+ /* Ownership of value transferred to dict. Therefore we must initalize
+ * it to NULL */
+ value = NULL;
+
+ /* Snap Timestamp */
+
+ /* convert time_t to tm struct. */
+ tmptr = localtime (&(entry->time_stamp));
+ if (NULL == tmptr) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to convert "
+ "time_t to *tm");
+ ret = -1;
+ goto out;
+ }
+
+ timestr = GF_CALLOC (1, maxstrlen, gf_gld_mt_char);
+ if (NULL == timestr) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Format time into string */
+ ret = strftime (timestr, maxstrlen, "%Y-%m-%d %H:%M:%S", tmptr);
+ if (0 == ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to convert time_t "
+ "to string");
+ ret = -1;
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.snap-time", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, timestr);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap time stamp in dictionary");
+ goto out;
+ }
+
+ /* Ownership of timestr transferred to dict. Therefore we must initalize
+ * it to NULL */
+ timestr = NULL;
+
+ if (!detail) {
+ /* If detail is not needed then return from here */
+ goto out;
+ }
+
+ /* Add detail */
+
+ /* If CG name is set the add the details in the dictionary */
+ if (0 != entry->cg_name[0] ) {
+ /* CG name */
+ value = gf_strdup (entry->cg_name);
+ if (NULL == value) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.cg-name", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap name in dictionary");
+ goto out;
+ }
+
+ /* CG ID */
+ value = gf_strdup (uuid_utoa (entry->cg_id));
+ if (NULL == value) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.cg-id", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "cg id in dictionary");
+ goto out;
+ }
+
+ /* Ownership of value transferred to dict. Therefore we must initalize
+ * it to NULL */
+ value = NULL;
+ }
+
+ /* If snap description is provided then add that into dictionary */
+ if (NULL != entry->description) {
+ /* Snap Description */
+ value = gf_strdup (entry->description);
+ if (NULL == value) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.snap-desc", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap description in dictionary");
+ goto out;
+ }
+ /* Ownership of value transferred to dict. Therefore we must initalize
+ * it to NULL */
+ value = NULL;
+ }
+
+ /* Snap status */
+ ret = snprintf (key, sizeof (key), "%s.snap-status", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ switch (entry->snap_status) {
+ case GD_SNAP_STATUS_INIT:
+ ret = dict_set_str (dict, key, "Init");
+ break;
+ case GD_SNAP_STATUS_IN_USE:
+ ret = dict_set_str (dict, key, "In-use");
+ break;
+ case GD_SNAP_STATUS_DECOMMISSION:
+ ret = dict_set_str (dict, key, "Decommisioned");
+ break;
+ case GD_SNAP_STATUS_RESTORED:
+ ret = dict_set_str (dict, key, "Restored");
+ break;
+ case GD_SNAP_STATUS_NONE:
+ ret = dict_set_str (dict, key, "None");
+ break;
+ default:
+ gf_log (this->name, GF_LOG_ERROR, "Invalid snap "
+ "status");
+ ret = -1;
+ goto out;
+ }
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap status in dictionary");
+ goto out;
+ }
+
+ ret = 0; /* Success */
+out:
+ if (NULL != value) {
+ GF_FREE (value);
+ }
+
+ if (NULL != timestr) {
+ GF_FREE(timestr);
+ }
+ return ret;
+}
+
+/* This function will retrieve the details of a single snap
+ * and then serialize them to dictionary (dict)
+ *
+ * @param dict dictionary where response should be serialized
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param entry Snap object
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_get_snapdetail (dict_t *dict, char *keyprefix,
+ glusterd_snap_t *entry,
+ int8_t detail)
+{
+ int ret = -1;
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (entry);
+
+ /* Acquire snap lock */
+ LOCK (&(entry->lock));
+ {
+ ret = glusterd_snapshot_get_snapdetail_lk (dict, keyprefix,
+ entry, detail);
+ }
+ UNLOCK (&(entry->lock));
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get snap detail");
+ }
+
+ return ret;
+}
+
+
+/* This function will retrieve snap list for the given volume
+ * and then serialize them to dict.
+ * This function is called under volinfo lock.
+ *
+ * @param dict dictionary where response should be serialized
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param volinfo Volinfo object of the volume
+ * @param snapname snap name. This field can be NULL
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_vol_get_snaplist_lk (dict_t *dict, char *keyprefix,
+ glusterd_volinfo_t *volinfo,
+ char *snapname, int8_t detail)
+{
+ int ret = -1;
+ ssize_t index = -1;
+ glusterd_snap_t *entry = NULL;
+ glusterd_snap_t *tmp = NULL;
+ xlator_t *this = NULL;
+ char *value = NULL;
+ char key[256];
+
+ this = THIS;
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (volinfo);
+
+ value = gf_strdup (volinfo->volname);
+ if (NULL == value) {
+ goto out;
+ }
+
+ /* First set the volume name */
+ ret = snprintf (key, sizeof (key), "%s.vol-name", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set volume name");
+ goto out;
+ }
+
+ /* Ownership of value transferred to dict. Therefore we must initalize
+ * it to NULL */
+ value = NULL;
+
+ /* New entries are always added to the end of snap_list and we need to
+ * display the list in LIFO (Last-In-First-Out) order. Therefore insert
+ * the entries in reverse order into the dictionary.
+ */
+ list_for_each_entry_safe_reverse (entry, tmp, &volinfo->snaps,
+ snap_list) {
+ ++index;
+ ret = snprintf (key, sizeof (key), "%s.snap%ld", keyprefix, index);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ /* If snapname is NULL then get all the snaps
+ * for the given volume */
+ if (NULL == snapname) {
+ ret = glusterd_snapshot_get_snapdetail (dict, key,
+ entry, detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ "get snap detail for %s snap",
+ snapname);
+ goto out; /* something wrong */
+ }
+ continue; /* Get the next entry */
+ }
+
+ /* If snapname is provided then get snap detail
+ * for only that snap */
+ if (strncmp (entry->snap_name, snapname,
+ sizeof (entry->snap_name))) {
+ /* Entry not yet found.*/
+ ret = -1;
+ continue; /* Check the next entry */
+ }
+
+ /* snap found */
+ ret = snprintf (key, sizeof (key), "%s.snap0", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = glusterd_snapshot_get_snapdetail (dict,
+ key, entry, detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get snap "
+ "detail for %s snap", snapname);
+ goto out;
+ }
+
+ /* Index is used to identify how many snap objects are
+ * added to the dictionary. If snapshot name is passed
+ * as argument then we would send only one snap object.
+ * Therefore index should be reset to 0. */
+ index = 0;
+ break; /* Found the snap */
+ }
+
+ /* If all the snap is written into the dictionary then write the
+ * snap count into the dictionary */
+ if (0 == ret) {
+ ++index; /* To get count increment index by 1*/
+ ret = snprintf (key, sizeof (key), "%s.snap-count", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_int64 (dict, key, index);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap count");
+ goto out;
+
+ }
+ } else if (NULL != snapname) {
+ gf_log (this->name, GF_LOG_ERROR, "Snap (%s) not found",
+ snapname);
+ }
+
+out:
+ if (NULL != value) {
+ GF_FREE (value);
+ }
+
+ return ret;
+}
+
+/* This function will retrieve snap list for the given volume
+ * and then serialize them to dict.
+ *
+ * @param dict dictionary where response should be serialized
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param volinfo Volinfo object of the volume
+ * @param snapname snap name. This field can be NULL
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_vol_get_snaplist (dict_t *dict, char *keyprefix,
+ glusterd_volinfo_t *volinfo,
+ char *snapname, int8_t detail)
+{
+ int ret = -1; /* Failure */
+ xlator_t *this = NULL;
+
+ this = THIS;
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (volinfo);
+
+ /* Acquire the volinfo lock before proceeding */
+ LOCK (&(volinfo->lock));
+ {
+ ret = glusterd_snapshot_vol_get_snaplist_lk (dict, keyprefix,
+ volinfo, snapname, detail);
+ }
+ UNLOCK (&(volinfo->lock));
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get snap list for"
+ " %s volume", volinfo->volname);
+ }
+
+ return ret;
+}
+
+
+/* This function will retrieve snap list for the given volume
+ * and then serialize them to dict.
+ *
+ * @param dict dictionary where response should be serialized
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param volname Volname whose snap list is requested
+ * @param snapname snap name. This field can be NULL.
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_vol_get_snaplist_by_name (dict_t *dict, char *keyprefix,
+ char *volname, char *snapname,
+ int8_t detail)
+{
+ int ret = -1;
+ glusterd_volinfo_t *volinfo = NULL;
+ xlator_t *this = NULL;
+
+ this = THIS;
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (volname);
+
+ /* Find te volinfo from the volname */
+ ret = glusterd_volinfo_find (volname, &volinfo);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get volinfo for "
+ "%s volume", volname);
+ goto out;
+ }
+
+ /* Now using the volinfo object get the snap list */
+ ret = glusterd_snapshot_vol_get_snaplist (dict, keyprefix, volinfo,
+ snapname, detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get snaplist for "
+ "%s volume", volname);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+
+
+/* This function will retrieve snap list for all the volumes
+ * present in a given CG and then serialize them to dict.
+ * This function is called under CG lock.
+ *
+ * @param dict dictionary where response should be serialized
+ * @param cg CG object which need to be written into dictionary
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param cgname CG name.
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_cg_get_snaplist_lk (dict_t *dict, glusterd_snap_cg_t *cg,
+ char *keyprefix, char *cgname,
+ int8_t detail)
+{
+ int ret = -1; /* Failure */
+ glusterd_conf_t *conf = NULL;
+ char *value = NULL;
+ xlator_t *this = NULL;
+ int64_t i = 0;
+ char key[256];
+
+ this = THIS;
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ conf = this->private;
+
+ GF_ASSERT (conf);
+ GF_ASSERT (dict);
+ GF_ASSERT (cg);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (cgname);
+
+ /* CG Name */
+ value = gf_strdup (cg->cg_name);
+ if (NULL == value) {
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.cg-name", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "cg name in dictionary");
+ goto out;
+ }
+
+ /* CG ID */
+ value = gf_strdup (uuid_utoa (cg->cg_id));
+ if (NULL == value) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.cg-id", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "cg id in dictionary");
+ goto out;
+ }
+
+ /* Ownership of value transferred to dict. Therefore we must initalize
+ * it to NULL */
+ value = NULL;
+
+ /* Volume count */
+ ret = snprintf (key, sizeof (key), "%s.vol-count", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_int64 (dict, key, cg->volume_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "volume count in dictionary");
+ goto out;
+ }
+
+ /* Get snap list for all volumes present in the CG */
+ for (i = 0; i < cg->volume_count; ++i) {
+ ret = snprintf (key, sizeof (key), "%s.vol%ld", keyprefix, i);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = glusterd_snapshot_vol_get_snaplist (dict, key,
+ &(cg->volumes[i]), NULL, detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get "
+ "snaplist for %s volume",
+ cg->volumes[i].volname);
+ goto out;
+ }
+ }
+
+ if (!detail) {
+ /* If detail is not needed then return from here */
+ goto out;
+ }
+
+ /* If CG description is provided then add that into dictionary */
+ if (NULL != cg->description) {
+ /* CG Description */
+ value = gf_strdup (cg->description);
+ if (NULL == value) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = snprintf (key, sizeof (key), "%s.cg-desc", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_dynstr (dict, key, value);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "cg description in dictionary");
+ goto out;
+ }
+
+ /* Ownership of value transferred to dict. Therefore we must initalize
+ * it to NULL */
+ value = NULL;
+ }
+
+
+ /* CG status */
+ ret = snprintf (key, sizeof (key), "%s.cg-status", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ switch (cg->cg_status) {
+ case GD_SNAP_STATUS_INIT:
+ ret = dict_set_str (dict, key, "Init");
+ break;
+ case GD_SNAP_STATUS_IN_USE:
+ ret = dict_set_str (dict, key, "In-use");
+ break;
+ case GD_SNAP_STATUS_DECOMMISSION:
+ ret = dict_set_str (dict, key, "Decommisioned");
+ break;
+ case GD_SNAP_STATUS_RESTORED:
+ ret = dict_set_str (dict, key, "Restored");
+ break;
+ case GD_SNAP_STATUS_NONE:
+ ret = dict_set_str (dict, key, "None");
+ break;
+ default:
+ gf_log (this->name, GF_LOG_ERROR, "Invalid snap "
+ "status");
+ ret = -1; /* Failure */
+ goto out;
+ }
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "snap status in dictionary");
+ goto out;
+ }
+
+ ret = 0;
+out:
+ if (NULL != value) {
+ GF_FREE (value);
+ }
+
+ return ret;
+}
+
+/* This function will retrieve snap list for all the volumes
+ * present in a given CG and then serialize them to dict.
+ *
+ * @param dict dictionary where response should be serialized
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param cgname CG name.
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_cg_get_snaplist (dict_t *dict, char *keyprefix,
+ char *cgname, int8_t detail)
+{
+ int ret = -1; /* Failure */
+ glusterd_conf_t *conf = NULL;
+ glusterd_snap_cg_t *cg = NULL;
+ xlator_t *this = NULL;
+
+ this = THIS;
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ conf = this->private;
+
+ GF_ASSERT (conf);
+ GF_ASSERT (dict);
+ GF_ASSERT (keyprefix);
+ GF_ASSERT (cgname);
+
+ /* Find the CG object from CG name */
+ cg = glusterd_find_snap_cg_by_name (conf, cgname);
+
+ if (NULL == cg) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get "
+ "%s CG", cgname);
+ goto out;
+ }
+
+ /* Got CG. Now serialize the CG content to dictionary */
+
+ LOCK (&(cg->lock));
+ {
+ ret = glusterd_snapshot_cg_get_snaplist_lk (dict, cg, keyprefix,
+ cgname, detail);
+ }
+ UNLOCK (&(cg->lock));
+
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get CG details");
+ }
+
+ ret = 0; /* Success */
+out:
+ return ret;
+}
+
+
+/* This function will retrieve snap list for all the volumes
+ * present in voldict dictionary. And then serialize them to
+ * rspdict.
+ *
+ * @param voldict dictionary containing volumes
+ * @param rspdict dictionary where response should be serialized
+ * @param volcount Total volume count
+ * @param keyprefix Prefix used for all the keys for rspdict dictionary
+ * @param snapname snap name. This field can be NULL.
+ * @param detail if 1 then more details will be added for snap list
+ *
+ * @return -1 on failure and 0 on success.
+ */
+static int
+glusterd_snapshot_get_snaplist (dict_t *voldict, dict_t *rspdict,
+ int64_t volcount, char* keyprefix,
+ char *snapname, int8_t detail)
+{
+ int ret = -1; /* Failure */
+ int64_t i = 0;
+ char *volname = NULL;
+ xlator_t *this = NULL;
+ char key[256];
+
+ this = THIS;
+
+ /* General parameter validation */
+ GF_ASSERT (this);
+ GF_ASSERT (voldict);
+ GF_ASSERT (rspdict);
+ GF_ASSERT (keyprefix);
+
+ /* Write the total volume count into the rspdict */
+ ret = snprintf (key, sizeof (key), "%s.vol-count", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_set_int64 (rspdict, key, volcount);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to set "
+ "volume count in dictionary");
+ goto out;
+ }
+
+ /* For each volume add all the snap list to rspdict dictionary */
+ for (i = 0; i < volcount; ++i) {
+ /* This key is used to get the volume name from voldict
+ * dictionary. Therefore do not use keyprefix here
+ */
+ ret = snprintf (key, sizeof (key), "vol%ld", i);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = dict_get_str (voldict, key, &volname);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ "volname for %s", key);
+ goto out;
+ }
+
+ /* Now for each volume get the snap list */
+ ret = snprintf (key, sizeof (key), "%s.vol%ld", keyprefix, i);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = glusterd_snapshot_vol_get_snaplist_by_name (rspdict, key,
+ volname, snapname, detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get "
+ "snapshot list for %s volume", volname);
+ goto out;
+ }
+ }
+
+ ret = 0; /* Success */
+out:
+ return ret;
+}
+
+
+
+/* This function will be called from RPC handler routine.
+ * This function is responsible for getting the requested
+ * snapshot list into the dictionary.
+ *
+ * @param req RPC request object. Required for sending a response back.
+ * @param op glusterd operation. Required for sending a response back.
+ * @param dict pointer to dictionary which will contain both
+ * request and response key-pair values.
+ * @return -1 on error and 0 on success
+ */
+int
+glusterd_handle_snapshot_list (rpcsvc_request_t *req, glusterd_op_t op,
+ dict_t *dict)
+{
+ int ret = -1;
+ int64_t volcount = 0;
+ int vol_count = 0;
+ int8_t detail = 0;
+ char *keyprefix = "snaplist";
+ char *cgname = NULL;
+ char *snapname = NULL;
+ dict_t *voldict = NULL;
+ xlator_t *this = NULL;
+ char *err_str = "Operation failed";
+ char key[256];
+
+ this = THIS;
+ GF_ASSERT (this);
+
+ GF_VALIDATE_OR_GOTO (this->name, req, out);
+ GF_VALIDATE_OR_GOTO (this->name, dict, out);
+
+ /* Get the request key-pair from the dictionary */
+
+ /* All these options are optonal. Therefore ignore
+ * error returned by following dictionary operations
+ */
+ ret = dict_get_str (dict, "snap-name", &snapname);
+ /* Ignore error */
+ ret = dict_get_int8 (dict, "snap-details", &detail);
+
+ ret = dict_get_int64 (dict, "vol-count", &volcount);
+ if (ret) {
+ /* Ignore error */
+ ret = dict_get_str (dict, "cg-name", &cgname);
+ }
+
+
+ /* If volume names are passed as argument then we should
+ * get all the snapshots for the said volumes.
+ */
+ if (volcount > 0) {
+ ret = glusterd_snapshot_get_snaplist (dict, dict, volcount,
+ keyprefix, snapname,
+ detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get "
+ "snapshot list");
+ goto out;
+ }
+ } else if (NULL != cgname) {
+ /* If CG (Consistency Group) name is passed as argument then
+ * we should get snapshots of all the volumes present in the
+ * said CG
+ */
+
+ /* TODO: Handle multiple CG if needed */
+ ret = snprintf (key, sizeof (key), "%s.cg0", keyprefix);
+ if (ret < 0) { /* Only negative value is error */
+ goto out;
+ }
+
+ ret = glusterd_snapshot_cg_get_snaplist (dict, key,
+ cgname, detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get "
+ "snapshot list for %s CG", cgname);
+ goto out;
+ }
+ } else {
+ /* If no argument is provided then we should get snapshots of
+ * all the volumes managed by this server
+ */
+
+ /* Create a dictionary to hold all the volumes retrieved from
+ * glusterd
+ */
+ voldict = dict_new ();
+ if (NULL == voldict) {
+ ret = -1;
+ goto out;
+ }
+
+ /* Get all the volumes from glusterd */
+ ret = glusterd_get_all_volnames (voldict);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get all "
+ "volume names");
+ goto out;
+ }
+
+ /* Get the volume count */
+ ret = dict_get_int32 (voldict, "vol-count", &vol_count);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get volume"
+ " count");
+ goto out;
+ }
+
+ volcount = vol_count;
+ /* Get snap list for all the volumes*/
+ ret = glusterd_snapshot_get_snaplist (voldict, dict, volcount,
+ keyprefix, NULL, detail);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to get "
+ "snapshot list");
+ goto out;
+ }
+ }
+
+ /* If everything is successful then send the response back to cli.
+ * In case of failure the caller of this function will take of response.*/
+ ret = glusterd_op_send_cli_response (op, 0, 0,
+ req, dict, err_str);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to send cli "
+ "response");
+ goto out;
+ }
+
+ ret = 0; /* Success */
+
+out:
+ if (voldict) {
+ dict_unref (voldict);
+ }
+ return ret;
+}
+
int
glusterd_handle_snapshot_fn (rpcsvc_request_t *req)
{
@@ -407,6 +1403,13 @@ glusterd_handle_snapshot_fn (rpcsvc_request_t *req)
case GF_SNAP_OPTION_TYPE_CREATE:
ret = glusterd_mgmt_v3_initiate_all_phases (req, cli_op, dict);
break;
+ case GF_SNAP_OPTION_TYPE_LIST:
+ ret = glusterd_handle_snapshot_list (req, cli_op, dict);
+ break;
+ default:
+ gf_log (this->name, GF_LOG_ERROR, "Unkown snapshot request "
+ "type (%d)", type);
+ ret = -1; /* Failure */
}
out:
@@ -427,21 +1430,3 @@ glusterd_handle_snapshot (rpcsvc_request_t *req)
{
return glusterd_big_locked_handler (req, glusterd_handle_snapshot_fn);
}
-
-int32_t
-glusterd_delete_snap_volume (glusterd_volinfo_t *volinfo,
- glusterd_volinfo_t *snapinfo)
-{
- int ret = -1;
- GF_ASSERT (volinfo);
-
- ret = glusterd_store_delete_volume (volinfo, snapinfo);
-
- if (ret)
- goto out;
-
- ret = glusterd_volinfo_delete (snapinfo);
-out:
- gf_log (THIS->name, GF_LOG_DEBUG, "returning %d", ret);
- return ret;
-}
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index 724618b..d51f8d2 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -335,6 +335,7 @@ struct glusterd_snap_ {
struct list_head snap_list;
char snap_name[256];
uuid_t snap_id;
+ char cg_name[256];
uuid_t cg_id;
char *description;
time_t time_stamp;