From 1aea4bdc774950f2d313bc541aaccf6d313aac88 Mon Sep 17 00:00:00 2001 From: Vijaikumar M Date: Thu, 20 Feb 2014 17:12:29 +0530 Subject: glusterd/snapshot: snapshot list and info changes This changes includes snap-driven based list and info changes: Change-Id: Ie82a2a3c785baa36892ca0cd97a958a2ae819d4c Signed-off-by: Vijaikumar M Signed-off-by: Sachin Pandit Reviewed-on: http://review.gluster.org/7139 Reviewed-by: Avra Sengupta Reviewed-by: Rajesh Joseph Tested-by: Rajesh Joseph --- xlators/mgmt/glusterd/src/glusterd-snapshot.c | 1229 +++++++++---------------- 1 file changed, 438 insertions(+), 791 deletions(-) (limited to 'xlators/mgmt/glusterd') diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c index e59aaa9ff..7bfede011 100644 --- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c @@ -1339,68 +1339,52 @@ out: return ret_1; } -/* 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) +glusterd_snapshot_get_snapvol_detail (dict_t *dict, + glusterd_volinfo_t *snap_vol, + char *keyprefix, int 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]; + int ret = -1; + int snap_limit = 0; + char key[PATH_MAX] = {0,}; + char *value = NULL; + glusterd_volinfo_t *origin_vol = NULL; + glusterd_conf_t *conf = NULL; + xlator_t *this = NULL; this = THIS; + conf = this->private; + GF_ASSERT (conf); - /* General parameter validation */ - GF_ASSERT (this); GF_ASSERT (dict); + GF_ASSERT (snap_vol); GF_ASSERT (keyprefix); - GF_ASSERT (entry); - /* Snap Name */ - value = gf_strdup (entry->snapname); - if (NULL == value) { + /* Volume Name */ + value = gf_strdup (snap_vol->volname); + if (!value) goto out; - } - snprintf (key, sizeof (key), "%s.snapname", keyprefix); + snprintf (key, sizeof (key), "%s.volname", keyprefix); ret = dict_set_dynstr (dict, key, value); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "snap name in dictionary"); + "volume name in dictionary: %s", key); goto out; } - /* Snap ID */ - value = gf_strdup (uuid_utoa (entry->snap_id)); + /* Volume ID */ + value = gf_strdup (uuid_utoa (snap_vol->volume_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; - } - + snprintf (key, sizeof (key), "%s.vol-id", keyprefix); ret = dict_set_dynstr (dict, key, value); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "snap id in dictionary"); + "volume id in dictionary: %s", key); goto out; } @@ -1408,578 +1392,133 @@ glusterd_snapshot_get_snapdetail_lk (dict_t *dict, char *keyprefix, * 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"); + /* volume status */ + snprintf (key, sizeof (key), "%s.vol-status", keyprefix); + switch (snap_vol->status) { + case GLUSTERD_STATUS_STARTED: + ret = dict_set_str (dict, key, "Started"); 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"); + case GLUSTERD_STATUS_STOPPED: + ret = dict_set_str (dict, key, "Stopped"); break; case GD_SNAP_STATUS_NONE: ret = dict_set_str (dict, key, "None"); break; default: - gf_log (this->name, GF_LOG_ERROR, "Invalid snap " + gf_log (this->name, GF_LOG_ERROR, "Invalid volume " "status"); ret = -1; goto out; } - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "snap status in dictionary"); + gf_log (this->name, GF_LOG_ERROR, "Failed to set volume status " + "in dictionary: %s", key); 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; - uint64_t index = 0; - glusterd_snap_t *entry = NULL; - glusterd_snap_t *tmp = NULL; - xlator_t *this = NULL; - char *value = NULL; - char key[256]; - glusterd_conf_t *conf = NULL; - uint64_t snap_limit = 0; - char err_str[PATH_MAX]; - - this = THIS; - - /* General parameter validation */ - GF_ASSERT (this); - GF_ASSERT (dict); - GF_ASSERT (keyprefix); - GF_ASSERT (volinfo); - - conf = this->private; - GF_ASSERT (conf); - - value = gf_strdup (volinfo->volname); - if (NULL == value) { + if (!detail) goto out; - } - - /* First set the volume name */ - ret = snprintf (key, sizeof (key), "%s.volname", keyprefix); - if (ret < 0) { /* Only negative value is error */ - goto out; - } - ret = dict_set_dynstr (dict, key, value); + ret = glusterd_volinfo_find (snap_vol->parent_volname, &origin_vol); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set volume name"); + gf_log (this->name, GF_LOG_ERROR, "failed to get the parent " + "volinfo for the volume %s", snap_vol->volname); goto out; } - ret = snprintf (key, sizeof (key), "%s.snap-count-total", keyprefix); - if (ret < 0) { - goto out; - } - - ret = dict_set_int64 (dict, key, volinfo->snap_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set total" - " snap count"); - goto out; - } - ret = snprintf (key, sizeof (key), "%s.snap-available", keyprefix); - if (ret < 0) { - goto out; - } - - if (conf->snap_max_hard_limit < volinfo->snap_max_hard_limit) { + /* Snaps available */ + if (conf->snap_max_hard_limit < origin_vol->snap_max_hard_limit) { snap_limit = conf->snap_max_hard_limit; gf_log(this->name, GF_LOG_DEBUG, "system snap-max-hard-limit is" " lesser than volume snap-max-hard-limit, " - "snap-max-hard-limit value is set to %ld", snap_limit); + "snap-max-hard-limit value is set to %d", snap_limit); } else { - snap_limit = volinfo->snap_max_hard_limit ; + snap_limit = origin_vol->snap_max_hard_limit ; gf_log(this->name, GF_LOG_DEBUG, "volume snap-max-hard-limit is" " lesser than system snap-max-hard-limit, " - "snap-max-hard-limit value is set to %ld",snap_limit); + "snap-max-hard-limit value is set to %d",snap_limit); } - if (snap_limit > volinfo->snap_count) - ret = dict_set_int64 (dict, key, - snap_limit - volinfo->snap_count); + snprintf (key, sizeof (key), "%s.snaps-available", keyprefix); + if (snap_limit > origin_vol->snap_count) + ret = dict_set_int32 (dict, key, + snap_limit - origin_vol->snap_count); else - ret = dict_set_int64 (dict, key, 0); + ret = dict_set_int32 (dict, key, 0); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to set available snaps"); goto out; } - /* Ownership of value transferred to dict. Therefore we must initalize - * it to NULL */ - value = NULL; - - /* snapshot taken first should be displayed first */ - list_for_each_entry_safe (entry, tmp, &conf->snapshots, - snap_list) { - ret = snprintf (key, sizeof (key), "%s.snap-%ld", keyprefix, - index); - if (ret < 0) { /* Only negative value is error */ - goto out; - } - ++index; - /* 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->snapname, snapname, - sizeof (entry->snapname))) { - /* Entry not yet found.*/ - ret = -1; - continue; /* Check the next entry */ - } - - /* snap found */ - ret = snprintf (key, sizeof (key), "%s.snap-0", 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 = 1; - break; /* Found the snap */ - } - - /* If all the snap is written into the dictionary then write the - * snap count into the dictionary */ - if (0 == ret) { - 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); - ret = snprintf (key, sizeof (key), "%s.err_str", - keyprefix); - if (ret < 0) { - goto out; - } - ret = snprintf (err_str, sizeof (err_str), "Snapshot %s" - " not found", snapname); - if (ret < 0) { - goto out; - } - ret = dict_set_str (dict, key, err_str); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to" - "set error string"); - goto out; - } - } - -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); + /* Parent volume name */ + value = gf_strdup (snap_vol->parent_volname); + if (!value) goto out; - } - /* Now using the volinfo object get the snap list */ - ret = glusterd_snapshot_vol_get_snaplist (dict, keyprefix, volinfo, - snapname, detail); + snprintf (key, sizeof (key), "%s.origin-volname", keyprefix); + ret = dict_set_dynstr (dict, key, value); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get snaplist for " - "%s volume", volname); + gf_log (this->name, GF_LOG_ERROR, "Failed to set parent " + "volume name in dictionary: %s", key); goto out; } + value = NULL; + ret = 0; /* Success */ out: + if (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. - * 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) +glusterd_snapshot_get_snap_detail (dict_t *dict, glusterd_snap_t *snap, + char *keyprefix, glusterd_volinfo_t *volinfo) { - int ret = -1; /* Failure */ - glusterd_conf_t *conf = NULL; - char *value = NULL; - xlator_t *this = NULL; - int64_t i = 0; - char key[256]= {0,}; - glusterd_volinfo_t *volinfo = NULL; + int ret = -1; + int volcount = 0; + char key[PATH_MAX] = {0,}; + char *value = NULL; + char *timestr = NULL; + struct tm *tmptr = NULL; + glusterd_volinfo_t *snap_vol = NULL; + glusterd_volinfo_t *tmp_vol = NULL; + xlator_t *this = NULL; this = THIS; - /* General parameter validation */ - GF_ASSERT (this); - conf = this->private; - - GF_ASSERT (conf); GF_ASSERT (dict); - GF_ASSERT (cg); + GF_ASSERT (snap); 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 */ + /* Snap Name */ + value = gf_strdup (snap->snapname); + if (!value) goto out; - } + snprintf (key, sizeof (key), "%s.snapname", keyprefix); ret = dict_set_dynstr (dict, key, value); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "cg name in dictionary"); + "snap name in dictionary"); goto out; } - /* CG ID */ - value = gf_strdup (uuid_utoa (cg->cg_id)); + /* Snap ID */ + value = gf_strdup (uuid_utoa (snap->snap_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; - } - + snprintf (key, sizeof (key), "%s.snap-id", keyprefix); ret = dict_set_dynstr (dict, key, value); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "cg id in dictionary"); + "snap id in dictionary"); goto out; } @@ -1987,75 +1526,64 @@ glusterd_snapshot_cg_get_snaplist_lk (dict_t *dict, glusterd_snap_cg_t *cg, * it to NULL */ value = NULL; - /* Volume count */ - ret = snprintf (key, sizeof (key), "%s.vol-count", keyprefix); - if (ret < 0) { /* Only negative value is error */ + /* Snap Timestamp */ + /* convert time_t to tm struct. */ + tmptr = localtime (&(snap->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, PATH_MAX, gf_gld_mt_char); + if (NULL == timestr) { + ret = -1; + goto out; + } + + /* Format time into string */ + ret = strftime (timestr, PATH_MAX, "%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 = dict_set_int64 (dict, key, cg->volume_count); + snprintf (key, sizeof (key), "%s.snap-time", keyprefix); + ret = dict_set_dynstr (dict, key, timestr); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "volume count in dictionary"); + "snap time stamp in dictionary"); goto out; } - /* Get snap list for all volumes present in the CG */ - for (i = 0; i < cg->volume_count; ++i) { - volinfo = cg->volumes[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, - volinfo, NULL, - detail); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get " - "snaplist for %s volume", volinfo->volname); - goto out; - } - } - - if (!detail) { - /* If detail is not needed then return from here */ - goto out; - } + /* Ownership of timestr transferred to dict. Therefore we must initalize + * it to NULL */ + timestr = NULL; - /* If CG description is provided then add that into dictionary */ - if (NULL != cg->description) { - /* CG Description */ - value = gf_strdup (cg->description); + /* If snap description is provided then add that into dictionary */ + if (NULL != snap->description) { + value = gf_strdup (snap->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; - } - + snprintf (key, sizeof (key), "%s.snap-desc", keyprefix); ret = dict_set_dynstr (dict, key, value); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "cg description in dictionary"); + "snap 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) { + /* Snap status */ + snprintf (key, sizeof (key), "%s.snap-status", keyprefix); + switch (snap->snap_status) { case GD_SNAP_STATUS_INIT: ret = dict_set_str (dict, key, "Init"); break; @@ -2074,77 +1602,95 @@ glusterd_snapshot_cg_get_snaplist_lk (dict_t *dict, glusterd_snap_cg_t *cg, default: gf_log (this->name, GF_LOG_ERROR, "Invalid snap " "status"); - ret = -1; /* Failure */ + ret = -1; + goto out; + } + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set snap status " + "in dictionary"); + goto out; + } + + if (volinfo) { + volcount = 1; + snprintf (key, sizeof (key), "%s.vol%d", keyprefix, volcount); + ret = glusterd_snapshot_get_snapvol_detail (dict, + volinfo, key, 0); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get volume detail %s for snap %s", + snap_vol->volname, snap->snapname); + goto out; + } + goto done; + } + + list_for_each_entry_safe (snap_vol, tmp_vol, &snap->volumes, vol_list) { + volcount++; + snprintf (key, sizeof (key), "%s.vol%d", keyprefix, volcount); + ret = glusterd_snapshot_get_snapvol_detail (dict, + snap_vol, key, 1); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get volume detail %s for snap %s", + snap_vol->volname, snap->snapname); goto out; + } } +done: + snprintf (key, sizeof (key), "%s.vol-count", keyprefix); + ret = dict_set_int32 (dict, key, volcount); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "snap status in dictionary"); + gf_log (this->name, GF_LOG_ERROR, "Failed to set %s", + key); goto out; } - ret = 0; + ret = 0; /* Success */ out: - if (NULL != value) { + if (value) GF_FREE (value); - } + + if (timestr) + GF_FREE(timestr); 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, - char *err_str, size_t len) +glusterd_snapshot_get_all_snap_info (dict_t *dict) { - int ret = -1; /* Failure */ - glusterd_conf_t *conf = NULL; - glusterd_snap_cg_t *cg = NULL; - xlator_t *this = NULL; + int ret = -1; + int snapcount = 0; + char key[PATH_MAX] = {0,}; + glusterd_snap_t *snap = NULL; + glusterd_snap_t *tmp_snap = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; this = THIS; + priv = this->private; + GF_ASSERT (priv); /* 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) { - snprintf (err_str, len, "CG %s not found", cgname); - gf_log (this->name, GF_LOG_WARNING, "%s", err_str); - ret = -1; - 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); + list_for_each_entry_safe (snap, tmp_snap, &priv->snapshots, snap_list) { + snapcount++; + snprintf (key, sizeof (key), "snap%d", snapcount); + ret = glusterd_snapshot_get_snap_detail (dict, snap, key, NULL); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get " + "snapdetail for snap %s", snap->snapname); + goto out; + } } - UNLOCK (&(cg->lock)); + ret = dict_set_int32 (dict, "snap-count", snapcount); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get CG details"); + gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount"); + goto out; } ret = 0; /* Success */ @@ -2152,121 +1698,103 @@ 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 +glusterd_snapshot_get_info_by_volume (dict_t *dict, char *volname) { - int ret = -1; /* Failure */ - int64_t i = 0; - char *volname = NULL; - xlator_t *this = NULL; - char key[256] = {0,}; - gf_boolean_t exist = _gf_false; - char *err_str = NULL; - char err_prefix[PATH_MAX] = ""; + int ret = -1; + int snapcount = 0; + int snap_limit = 0; + char *value = NULL; + char key[PATH_MAX] = ""; + glusterd_volinfo_t *volinfo = NULL; + glusterd_volinfo_t *snap_vol = NULL; + glusterd_volinfo_t *tmp_vol = NULL; + glusterd_conf_t *conf = NULL; + xlator_t *this = NULL; this = THIS; + conf = this->private; + GF_ASSERT (conf); - /* General parameter validation */ - GF_ASSERT (this); - GF_ASSERT (voldict); - GF_ASSERT (rspdict); - GF_ASSERT (keyprefix); + GF_ASSERT (dict); + GF_ASSERT (volname); - /* 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 */ + 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_set_int64 (rspdict, key, volcount); + /* Snaps available */ + if (conf->snap_max_hard_limit < volinfo->snap_max_hard_limit) { + snap_limit = conf->snap_max_hard_limit; + gf_log(this->name, GF_LOG_DEBUG, "system snap-max-hard-limit is" + " lesser than volume snap-max-hard-limit, " + "snap-max-hard-limit value is set to %d", snap_limit); + } + else { + snap_limit = volinfo->snap_max_hard_limit ; + gf_log(this->name, GF_LOG_DEBUG, "volume snap-max-hard-limit is" + " lesser than system snap-max-hard-limit, " + "snap-max-hard-limit value is set to %d",snap_limit); + } + + if (snap_limit > volinfo->snap_count) + ret = dict_set_int32 (dict, "snaps-available", + snap_limit - volinfo->snap_count); + else + ret = dict_set_int32 (dict, "snaps-available", 0); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "volume count in dictionary"); + gf_log (this->name, GF_LOG_ERROR, + "Failed to set available snaps"); 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 get" - "volname for %s", key); - goto out; - } - - ret = snprintf (key, sizeof (key), "%s.vol%ld", keyprefix, i); - if (ret < 0) { /* Only negative value is error */ - goto out; - } + /* Origin volume name */ + value = gf_strdup (volinfo->volname); + if (!value) + goto out; - exist = glusterd_check_volume_exists (volname); - if (!exist) { - err_str = (char *) GF_CALLOC(1, PATH_MAX, sizeof(char)); - gf_log ("", GF_LOG_ERROR, - "Volume %s Does not exist", volname); - ret = snprintf (err_str, PATH_MAX, - "Volume %s Does not exist",volname); - if (ret < 0) { - goto out; - } - ret = snprintf (err_prefix, sizeof (err_prefix), - "%s.err_str", key); - if (ret < 0) { - goto out; - } - ret = dict_set_str (rspdict, err_prefix, err_str); - if (ret < 0 ) { - gf_log ("", GF_LOG_ERROR, "Could not" - "save the err_str"); - goto out; - } - continue; - } + ret = dict_set_dynstr (dict, "origin-volname", value); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set parent " + "volume name in dictionary: %s", key); + goto out; + } + value = NULL; - /* Now for each volume get the snap list */ - ret = glusterd_snapshot_vol_get_snaplist_by_name (rspdict, key, - volname, snapname, detail); + list_for_each_entry_safe (snap_vol, tmp_vol, &volinfo->snap_volumes, + snapvol_list) { + snapcount++; + snprintf (key, sizeof (key), "snap%d", snapcount); + ret = glusterd_snapshot_get_snap_detail (dict, + snap_vol->snapshot, + key, snap_vol); if (ret) { gf_log (this->name, GF_LOG_ERROR, "Failed to get " - "snapshot list for %s volume", volname); + "snapdetail for snap %s", + snap_vol->snapshot->snapname); goto out; } } + ret = dict_set_int32 (dict, "snap-count", snapcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount"); + goto out; + } - ret = 0; /* Success */ + ret = 0; out: + if (value) + GF_FREE (value); + return ret; } - - /* This function will be called from RPC handler routine. * This function is responsible for getting the requested - * snapshot list into the dictionary. + * snapshot info into the dictionary. * * @param req RPC request object. Required for sending a response back. * @param op glusterd operation. Required for sending a response back. @@ -2275,19 +1803,15 @@ out: * @return -1 on error and 0 on success */ int -glusterd_handle_snapshot_list (rpcsvc_request_t *req, glusterd_op_t op, +glusterd_handle_snapshot_info (rpcsvc_request_t *req, glusterd_op_t op, dict_t *dict, char *err_str, size_t len) { - 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 key[256] = {0,}; + int ret = -1; + int8_t snap_driven = 0; + char *volname = NULL; + char *snapname = NULL; + glusterd_snap_t *snap = NULL; + xlator_t *this = NULL; this = THIS; GF_ASSERT (this); @@ -2301,92 +1825,209 @@ glusterd_handle_snapshot_list (rpcsvc_request_t *req, glusterd_op_t op, * error returned by following dictionary operations */ ret = dict_get_str (dict, "snapname", &snapname); - /* Ignore error */ - ret = dict_get_int8 (dict, "snap-details", &detail); + ret = dict_get_str (dict, "volname", &volname); - ret = dict_get_int64 (dict, "vol-count", &volcount); - if (ret) { - /* Ignore error */ - ret = dict_get_str (dict, "cgname", &cgname); + if (snapname && volname) { + gf_log (this->name, GF_LOG_ERROR, "Option volname and snapname " + "are mutually exclusive"); + ret = -1; + goto out; } + if (!volname) + snap_driven = 1; - /* 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); + ret = dict_set_int8 (dict, "snap-driven", snap_driven); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set snap-driven"); + goto out; + } + + if (snapname) { + ret = dict_set_int32 (dict, "snap-count", 1); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get " - "snapshot list"); + gf_log (this->name, GF_LOG_ERROR, + "Failed to set snapcount"); 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.cg-0", keyprefix); - if (ret < 0) { /* Only negative value is error */ + snap = glusterd_find_snap_by_name (snapname); + if (!snap) { + gf_log (this->name, GF_LOG_ERROR, "Snap %s doen't " + "exist", snapname); + ret = -1; goto out; } + ret = glusterd_snapshot_get_snap_detail (dict, snap, "snap1", + NULL); + } else if (volname) { + ret = glusterd_snapshot_get_info_by_volume (dict, volname); + } else { + ret = glusterd_snapshot_get_all_snap_info (dict); + } - ret = glusterd_snapshot_cg_get_snaplist (dict, key, cgname, - detail, err_str, len); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get snap info"); + 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: + return ret; +} + +/* Function glusterd_snapshot_get_list1 sets all the snapshot names + in the dictionary */ +int +glusterd_snapshot_get_list1 (dict_t *dict) +{ + int ret = -1; + int snapcount = 0; + char *snapname = NULL; + char key[PATH_MAX] = {0,}; + glusterd_snap_t *snap = NULL; + glusterd_snap_t *tmp_snap = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + this = THIS; + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (dict); + + list_for_each_entry_safe (snap, tmp_snap, &priv->snapshots, snap_list) { + snapcount++; + snapname = gf_strdup (snap->snapname); + if (!snapname) { + gf_log (this->name, GF_LOG_ERROR, "strdup failed"); + ret = -1; + goto out; + } + snprintf (key, sizeof (key), "snapname%d", snapcount); + ret = dict_set_dynstr (dict, key, snapname); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get " - "snapshot list for %s CG", cgname); + GF_FREE (snapname); + gf_log (this->name, GF_LOG_ERROR, "Failed to set %s", + key); 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 = dict_set_int32 (dict, "snap-count", snapcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount"); + goto out; + } + + ret = 0; +out: + + return ret; +} + +/* Function glusterd_snapshot_get_list2 sets all the snapshot names + under a given volume in the dictionary */ +int +glusterd_snapshot_get_list2 (dict_t *dict, glusterd_volinfo_t *volinfo) +{ + int ret = -1; + int snapcount = 0; + char *snapname = NULL; + char key[PATH_MAX] = {0,}; + glusterd_volinfo_t *snap_vol = NULL; + glusterd_volinfo_t *tmp_vol = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (dict); + GF_ASSERT (volinfo); + + list_for_each_entry_safe (snap_vol, tmp_vol, + &volinfo->snap_volumes, snapvol_list) { + snapcount++; + snapname = gf_strdup (snap_vol->snapshot->snapname); + if (!snapname) { + gf_log (this->name, GF_LOG_ERROR, + "strdup failed"); ret = -1; goto out; } - - /* Get all the volumes from glusterd */ - ret = glusterd_get_all_volnames (voldict); + snprintf (key, sizeof (key), "snapname%d", snapcount); + ret = dict_set_dynstr (dict, key, snapname); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get all " - "volume names"); + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "set %s", key); + GF_FREE (snapname); goto out; } + } + + ret = dict_set_int32 (dict, "snap-count", snapcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set snapcount"); + goto out; + } + + ret = 0; +out: - /* Get the volume count */ - ret = dict_get_int32 (voldict, "vol_count", &vol_count); + return ret; +} + +int +glusterd_handle_snapshot_list (rpcsvc_request_t *req, glusterd_op_t op, + dict_t *dict, char *err_str, size_t len) +{ + int ret = -1; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + xlator_t *this = NULL; + + this = THIS; + + GF_VALIDATE_OR_GOTO (this->name, req, out); + GF_VALIDATE_OR_GOTO (this->name, dict, out); + + /* Ignore error for getting volname as it is optional */ + ret = dict_get_str (dict, "volname", &volname); + + if (NULL == volname) { + ret = glusterd_snapshot_get_list1 (dict); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to get snapshot list"); + goto out; + } + } else { + ret = glusterd_volinfo_find (volname, &volinfo); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get volume" - " count"); + gf_log (this->name, GF_LOG_ERROR, + "Volume %s doesn't exists", volname); goto out; } - volcount = vol_count; - /* Get snap list for all the volumes*/ - ret = glusterd_snapshot_get_snaplist (voldict, dict, volcount, - keyprefix, NULL, detail); + ret = glusterd_snapshot_get_list2 (dict, volinfo); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get " - "snapshot list"); + gf_log (this->name, GF_LOG_ERROR, + "Failed to get snapshot list for volume %s", + volname); 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); + 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"); @@ -2396,9 +2037,6 @@ glusterd_handle_snapshot_list (rpcsvc_request_t *req, glusterd_op_t op, ret = 0; /* Success */ out: - if (voldict) { - dict_unref (voldict); - } return ret; } @@ -3450,6 +3088,7 @@ glusterd_handle_snapshot_remove (rpcsvc_request_t *req, glusterd_op_t op, xlator_t *this = NULL; this = THIS; + GF_ASSERT (req); GF_ASSERT (dict); GF_ASSERT (err_str); @@ -4340,6 +3979,14 @@ glusterd_handle_snapshot_fn (rpcsvc_request_t *req) "failed: %s", err_str); } + break; + case GF_SNAP_OPTION_TYPE_INFO: + ret = glusterd_handle_snapshot_info (req, cli_op, dict, + err_str, sizeof (err_str)); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Snapshot info " + "failed"); + } break; case GF_SNAP_OPTION_TYPE_LIST: ret = glusterd_handle_snapshot_list (req, cli_op, dict, -- cgit