summaryrefslogtreecommitdiffstats
path: root/xlators/mgmt/glusterd/src/glusterd-volgen.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-volgen.c')
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-volgen.c514
1 files changed, 507 insertions, 7 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c
index 1bc0db6ce..3b8e7648c 100644
--- a/xlators/mgmt/glusterd/src/glusterd-volgen.c
+++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c
@@ -28,6 +28,8 @@
#include "logging.h"
#include "dict.h"
#include "graph-utils.h"
+#include "glusterd-store.h"
+#include "glusterd-hooks.h"
#include "trie.h"
#include "glusterd-mem-types.h"
#include "cli1-xdr.h"
@@ -3175,7 +3177,8 @@ glusterd_generate_brick_volfile (glusterd_volinfo_t *volinfo,
static int
glusterd_generate_snap_brick_volfile (glusterd_volinfo_t *volinfo,
glusterd_brickinfo_t *brickinfo,
- glusterd_volinfo_t *snap_volinfo)
+ glusterd_volinfo_t *snap_volinfo,
+ gf_boolean_t vol_restore)
{
volgen_graph_t graph = {0,};
char filename[PATH_MAX] = {0,};
@@ -3189,7 +3192,16 @@ glusterd_generate_snap_brick_volfile (glusterd_volinfo_t *volinfo,
GF_ASSERT (brickinfo);
GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, brick);
- GLUSTERD_GET_SNAP_DIR (path, volinfo, snap_volinfo->volname, priv);
+ /* If the brick volfile is generated as part of a restore
+ * operation then we should be generating the brick volfile
+ * in the origin volume folder instead of snap volume folder.
+ */
+ if (vol_restore) {
+ GLUSTERD_GET_VOLUME_DIR (path, volinfo, priv);
+ } else {
+ GLUSTERD_GET_SNAP_DIR (path, volinfo,
+ snap_volinfo->volname, priv);
+ }
snprintf (filename, PATH_MAX, "%s/%s.%s.%s.vol",
path, snap_volinfo->volname,
@@ -3285,8 +3297,10 @@ generate_snap_brick_volfiles (glusterd_volinfo_t *volinfo,
"Found a brick - %s:%s", brickinfo->hostname,
brickinfo->path);
- ret = glusterd_generate_snap_brick_volfile (volinfo, brickinfo,
- snap_volinfo);
+ ret = glusterd_generate_snap_brick_volfile (volinfo,
+ brickinfo,
+ snap_volinfo,
+ _gf_false);
if (ret)
goto out;
}
@@ -3382,7 +3396,8 @@ out:
int
generate_snap_client_volfiles (glusterd_volinfo_t *actual_volinfo,
glusterd_volinfo_t *snap_volinfo,
- glusterd_client_type_t client_type)
+ glusterd_client_type_t client_type,
+ gf_boolean_t vol_restore)
{
char filepath[PATH_MAX] = {0,};
int ret = -1;
@@ -3416,6 +3431,18 @@ generate_snap_client_volfiles (glusterd_volinfo_t *actual_volinfo,
dict = dict_new ();
if (!dict)
goto out;
+
+ /* If the brick volfile is generated as part of a restore
+ * operation then we should be generating the brick volfile
+ * in the origin volume folder instead of snap volume folder.
+ */
+ if (vol_restore) {
+ GLUSTERD_GET_VOLUME_DIR (path, actual_volinfo, conf);
+ } else {
+ GLUSTERD_GET_SNAP_DIR (path, actual_volinfo,
+ snap_volinfo->volname, conf);
+ }
+
for (i = 0; types[i]; i++) {
memset (filepath, 0, sizeof (filepath));
ret = dict_set_str (dict, "client-transport-type", types[i]);
@@ -3427,8 +3454,6 @@ generate_snap_client_volfiles (glusterd_volinfo_t *actual_volinfo,
if (ret)
goto out;
- GLUSTERD_GET_SNAP_DIR (path, actual_volinfo,
- snap_volinfo->volname,conf);
if (client_type == GF_CLIENT_TRUSTED) {
if ((actual_volinfo->transport_type ==
GF_TRANSPORT_BOTH_TCP_RDMA) &&
@@ -4115,3 +4140,478 @@ gd_is_boolean_option (char *key)
return _gf_false;
}
+
+/* This is a utility function which will create backup of
+ * origin volume file and then replace the origin volume
+ * file with a sym-link to snap volume file.
+ *
+ * @param orig_vol volinfo of origin volume
+ * @param orig_file file belonging to origin volume
+ * @param snap_file corresponding file in snap volume
+ *
+ * @return 0 on success and negative value on failure.
+ */
+static int
+gd_backup_and_restore_snap_files (glusterd_volinfo_t *orig_vol,
+ const char *orig_file,
+ const char *snap_file)
+{
+ int ret = -1;
+ char tmppath[PATH_MAX] = {0,};
+ xlator_t *this = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ GF_ASSERT (orig_vol);
+ GF_ASSERT (orig_file);
+ GF_ASSERT (snap_file);
+
+ /* If the volume is already a restored volume then we
+ * need not create a backup of files belonging to origin
+ * volume.
+ * We can simply delete the sym-link created by previous
+ * restore.
+ */
+ if (orig_vol->is_volume_restored) {
+ ret = remove (orig_file);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ "remove %s file", orig_file);
+ goto out;
+ }
+ } else {
+ snprintf (tmppath, sizeof (tmppath), "%s.origin",
+ orig_file);
+ /* TODO: These temp files need to be deleted once the restored
+ * operation is successful
+ */
+
+ /* Create backup of origin volume file */
+ ret = rename (orig_file, tmppath);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to rename "
+ "file from %s to %s", orig_file, tmppath);
+ goto out;
+ }
+ }
+
+ /* Create sym-link to snap file */
+ ret = symlink (snap_file, orig_file);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to create sym-link "
+ "to %s file", snap_file);
+ goto out;
+ }
+
+ ret = 0;
+out:
+
+ return ret;
+}
+
+/* This is a utility function which will create a backup copy
+ * of origin volume.
+ *
+ * @param origvol volinfo of origin volume
+ * @param fileformat This string provides formatting information
+ * for the file to be backed up. The format
+ * string should be of <string>%s<string> format.
+ * Where <string> can be any string and this
+ * function will replace %s with origin volume
+ * name. e.g. "trusted-%s-fuse.vol".
+ * @param volpath volume path
+ *
+ * @return 0 on success and negative value on failure.
+ */
+static inline int
+gd_format_path_and_backup_snap_files (glusterd_volinfo_t *origvol,
+ const char *fileformat,
+ const char *volpath)
+{
+ int ret = -1;
+ char origfile[PATH_MAX] = {0,};
+ char formatstr[PATH_MAX] = {0,};
+ char tmppath[PATH_MAX] = {0,};
+
+ snprintf (formatstr, sizeof (formatstr), "%s/%s", volpath, fileformat);
+ snprintf (origfile, sizeof (origfile), formatstr, origvol->volname);
+
+ /* If the volume is already a restored volume then we
+ * need not create a backup of files belonging to origin
+ * volume.
+ * We can simply delete the sym-link created by previous
+ * restore.
+ */
+ if (origvol->is_volume_restored) {
+ ret = remove (origfile);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "Failed to "
+ "remove %s file", origfile);
+ }
+ goto out;
+ }
+
+ snprintf (tmppath, sizeof (tmppath), "%s.origin", origfile);
+
+ /* Create a backup of this file */
+ ret = rename (origfile, tmppath);
+ if (ret) {
+ gf_log (THIS->name, GF_LOG_ERROR, "failed to restore %s file",
+ origfile);
+ }
+
+out:
+ return ret;
+}
+
+/* This is a utility function which will backup the origin volume
+ * brick folder and then create sym link to the snap_vol brick
+ * folder.
+ *
+ * @param orig_vol volinfo of origin volume
+ * @param snap_vol volinfo of snap volume
+ *
+ * @return 0 on success and negative value on failure.
+ */
+static int
+gd_restore_snap_brick_vol_files (glusterd_volinfo_t *orig_vol,
+ glusterd_volinfo_t *snap_vol)
+{
+ int ret = -1;
+ char path[PATH_MAX] = {0,};
+ char brick[PATH_MAX] = {0,};
+ char oldfilename[PATH_MAX] = {0,};
+ char newfilename[PATH_MAX] = {0,};
+ glusterd_brickinfo_t *brickinfo = NULL;
+ xlator_t *this = NULL;
+ glusterd_conf_t *conf = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ conf = this->private;
+ GF_ASSERT (conf);
+
+ GLUSTERD_GET_VOLUME_DIR (path, orig_vol, conf);
+
+ /* brick count of origin volume and snapshot volume might be
+ * different. Therefore we need to run two different loop to
+ * restore snap brick vol files.
+ */
+ list_for_each_entry (brickinfo, &orig_vol->bricks, brick_list) {
+ GLUSTERD_REMOVE_SLASH_FROM_PATH (brickinfo->path, brick);
+
+ snprintf (oldfilename, sizeof (oldfilename), "%s/%s.%s.%s.vol",
+ path, orig_vol->volname, brickinfo->hostname,
+ brick);
+
+ /* If the volume is already a restored volume then we
+ * need not create a backup of files belonging to origin
+ * volume.
+ * We can simply delete the sym-link created by previous
+ * restore.
+ */
+ if (orig_vol->is_volume_restored) {
+ ret = remove (oldfilename);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ "remove %s file", oldfilename);
+ goto out;
+ }
+ continue;
+ }
+
+ snprintf (newfilename, sizeof (newfilename), "%s.origin",
+ oldfilename);
+
+ /* Create a backup of origin volume file */
+ ret = rename (oldfilename, newfilename);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to rename "
+ "file from %s to %s", oldfilename,
+ newfilename);
+ goto out;
+ }
+ }
+
+ /* Recreate brick files for origin volume */
+ list_for_each_entry (brickinfo, &snap_vol->bricks, brick_list) {
+ ret = glusterd_generate_snap_brick_volfile (orig_vol,
+ brickinfo,
+ snap_vol,
+ _gf_true);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to generate "
+ "brick volfile");
+ goto out;
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+
+/* This function will update the in-memory representation
+ * of the origin volume with the snap volume details.
+ *
+ * @param orig_vol origin volume volinfo
+ * @param snap_vol snap volume volinfo
+ *
+ * @return 0 on success and negative value on failure.
+ */
+static int
+gd_update_origin_volume (glusterd_volinfo_t *orig_vol,
+ glusterd_volinfo_t *snap_vol)
+{
+ int ret = -1;
+ xlator_t *this = NULL;
+ glusterd_conf_t *conf = NULL;
+ glusterd_brickinfo_t *brickinfo = NULL;
+
+ this = THIS;
+ GF_ASSERT (this);
+ conf = this->private;
+ GF_ASSERT (conf);
+ GF_ASSERT (orig_vol);
+ GF_ASSERT (snap_vol);
+
+ /* Update the in-memory volinfo from the store */
+ ret = glusterd_store_update_volinfo (orig_vol, NULL);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to update "
+ "volinfo for %s volume", orig_vol->volname);
+ goto out;
+ }
+
+ /* Reset the port number to 0 */
+ orig_vol->port = 0;
+ /* Reset the volume status to stopped */
+ glusterd_set_volume_status (orig_vol, GLUSTERD_STATUS_STOPPED);
+
+ /* Stop the snap volume */
+ list_for_each_entry (brickinfo, &snap_vol->bricks, brick_list) {
+ ret = glusterd_snap_brick_stop (orig_vol, snap_vol,
+ brickinfo, _gf_false);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to stop "
+ " %s brick", brickinfo->path);
+ goto out;
+ }
+ }
+
+ /* Set the volume status to stopped for the snap volume */
+ glusterd_set_volume_status (snap_vol, GLUSTERD_STATUS_STOPPED);
+
+ /* The in-memory brick list for the origin volume should be
+ * replaced with the brick list of snap volume. Therefore
+ * first delete all the bricks from the origin volume and
+ * then read the brick list from the store which is already
+ * updated
+ */
+
+ /* Delete previous brick infos */
+ ret = glusterd_volume_brickinfos_delete (orig_vol);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to delete "
+ "brickinfos for %s volume", orig_vol->volname);
+ goto out;
+ }
+
+ /* Retrieve brick list */
+ ret = glusterd_store_retrieve_bricks (orig_vol, NULL);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to retrieve "
+ "bricks info from store for %s volume",
+ orig_vol->volname);
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+/* This function will restore origin volume to it it's snap.
+ * The restore operation will simply replace the Gluster origin
+ * volume with the snap volume.
+ *
+ * @param orig_vol volinfo of origin volume
+ * @param snap_vol volinfo of snapshot volume
+ *
+ * @return 0 on success and negative value on error
+ */
+int
+gd_restore_snap_volume (glusterd_volinfo_t *orig_vol,
+ glusterd_volinfo_t *snap_vol)
+{
+ int ret = -1;
+ unsigned int i = 0;
+ char snappath[PATH_MAX] = {0,};
+ char volpath[PATH_MAX] = {0,};
+ char oldfilename[PATH_MAX] = {0,};
+ char newfilename[PATH_MAX] = {0,};
+ char *types[] = {NULL, NULL, NULL};
+ xlator_t *this = NULL;
+ glusterd_conf_t *conf = NULL;
+ gf_transport_type type = GF_TRANSPORT_TCP;
+ char tmpname[GLUSTERD_MAX_VOLUME_NAME] = {0,};
+
+ this = THIS;
+ GF_ASSERT (this);
+ conf = this->private;
+ GF_ASSERT (conf);
+
+ GF_VALIDATE_OR_GOTO (this->name, orig_vol, out);
+ GF_VALIDATE_OR_GOTO (this->name, snap_vol, out);
+
+ GLUSTERD_GET_SNAP_DIR (snappath, orig_vol, snap_vol->volname, conf);
+ GLUSTERD_GET_VOLUME_DIR (volpath, orig_vol, conf);
+
+ /* As mentioned earlier the snapshot restore is done by replacing
+ * the origin volume with the snapshot volume. To do so we have to
+ * replace all backend files belonging to origin volume with the
+ * snapshot volume. And once all the backend files are updated
+ * update the in-memory structure of the origin volume. Also delete
+ * the snapshot volume.
+ * TODO: deleting of snapshot volume can be controlled by user
+ * controllable option.
+ */
+
+ /* Backup and restore info file */
+ ret = gd_backup_and_restore_snap_files (orig_vol,
+ orig_vol->shandle->path,
+ snap_vol->shandle->path);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to restore info "
+ "file for %s volume", orig_vol->volname);
+ goto out;
+ }
+
+ GLUSTERD_GET_BRICK_DIR (oldfilename, orig_vol, conf);
+ GLUSTERD_GET_SNAP_BRICK_DIR (newfilename, orig_vol,
+ snap_vol->volname, conf);
+
+ /* Backup and restore bricks folder and it's contents */
+ ret = gd_backup_and_restore_snap_files (orig_vol, oldfilename,
+ newfilename);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to restore bricks "
+ "folder for %s volume", orig_vol->volname);
+ goto out;
+ }
+
+ enumerate_transport_reqs (orig_vol->transport_type, types);
+
+
+ for (i = 0; NULL != types[i]; i++) {
+ type = transport_str_to_type (types[i]);
+
+ if ((orig_vol->transport_type == GF_TRANSPORT_BOTH_TCP_RDMA) &&
+ type == GF_TRANSPORT_RDMA) {
+ /* Backup trusted rdma-fuse.vol file */
+ ret = gd_format_path_and_backup_snap_files (orig_vol,
+ "trusted-%s.rdma-fuse.vol",
+ volpath);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ " backup trusted*.rdma-fuse.vol file");
+ goto out;
+ }
+
+ /* Backup rdma-fuse.vol file */
+ ret = gd_format_path_and_backup_snap_files (orig_vol,
+ "%s.rdma-fuse.vol", volpath);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ " backup rdma-fuse.vol file");
+ goto out;
+ }
+ } else {
+ /* Backup trusted fuse.vol file */
+ ret = gd_format_path_and_backup_snap_files (orig_vol,
+ "trusted-%s-fuse.vol", volpath);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ " backup trusted*-fuse.vol file");
+ goto out;
+ }
+
+ /* Backup fuse.vol file */
+ ret = gd_format_path_and_backup_snap_files (orig_vol,
+ "%s-fuse.vol", volpath);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to "
+ " backup fuse.vol file");
+ goto out;
+ }
+ }
+ }
+
+ /* The restored client and brick vol files should have all
+ * the entries present in snap vol files but the volume name
+ * for all these entries should still be the origin volume
+ * name.
+ * As of now these volfile generation takes volume name
+ * directly from the volinfo. Therefore instead of changing
+ * all the generate function simply replace the snap volume
+ * name with the origin volume name. And once the vol files
+ * are generated restore the volume name.
+ */
+ strncpy (tmpname, snap_vol->volname, sizeof(tmpname));
+ strncpy (snap_vol->volname, orig_vol->volname,
+ sizeof(snap_vol->volname));
+
+ /* Generate trusted client vol file */
+ ret = generate_snap_client_volfiles (orig_vol, snap_vol,
+ GF_CLIENT_TRUSTED, _gf_true);
+ if (ret) {
+ /* Restore the snap volume name */
+ strncpy (snap_vol->volname, tmpname, sizeof(snap_vol->volname));
+ gf_log (this->name, GF_LOG_ERROR, "Failed to generated "
+ " trusted client vol file for %s volume",
+ orig_vol->volname);
+ goto out;
+ }
+
+ ret = generate_snap_client_volfiles (orig_vol, snap_vol,
+ GF_CLIENT_OTHER, _gf_true);
+ if (ret) {
+ /* Restore the snap volume name */
+ strncpy (snap_vol->volname, tmpname, sizeof(snap_vol->volname));
+ gf_log (this->name, GF_LOG_ERROR, "Failed to generated "
+ " client vol file for %s volume", orig_vol->volname);
+ goto out;
+ }
+
+ ret = gd_restore_snap_brick_vol_files (orig_vol, snap_vol);
+ if (ret) {
+ /* Restore the snap volume name */
+ strncpy (snap_vol->volname, tmpname, sizeof(snap_vol->volname));
+ gf_log (this->name, GF_LOG_ERROR, "Failed to generated "
+ " brick vol files for %s volume", orig_vol->volname);
+ goto out;
+ }
+
+ /* Restore the snap volume name */
+ strncpy (snap_vol->volname, tmpname, sizeof(snap_vol->volname));
+
+ /* Update the in-memory structure of origin volume */
+ ret = gd_update_origin_volume (orig_vol, snap_vol);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to update "
+ "origin volume %s", orig_vol->volname);
+ goto out;
+ }
+
+ /* Update status to restored */
+ orig_vol->is_volume_restored = _gf_true;
+
+ ret = glusterd_store_volinfo (orig_vol, GLUSTERD_VOLINFO_VER_AC_NONE);
+ if (ret) {
+ gf_log (this->name, GF_LOG_ERROR, "Failed to store volume "
+ "info of %s volume", orig_vol->volname);
+ goto out;
+ }
+out:
+ return ret;
+}