From 8f87071658ae8d0799f752a9f7f951fbd46ceda7 Mon Sep 17 00:00:00 2001 From: Rajesh Joseph Date: Wed, 5 Mar 2014 18:26:37 +0530 Subject: glusterd/snapshot: Modified restore backend Now instead of creating volume store files first we constructing the in-memory volinfo first and then generate the backend store files. This gives lot of flexibility in restore operation. This patch also fixes the read-only issue with restored snaps. Change-Id: I51032228a5212fc3b90dc6e93f3539af3eb36074 BUG: 1064688 Signed-off-by: Rajesh Joseph Reviewed-on: http://review.gluster.org/7209 Reviewed-by: Sachin Pandit Reviewed-by: Vijaikumar Mallikarjuna --- xlators/mgmt/glusterd/src/glusterd-volgen.c | 479 ++++------------------------ 1 file changed, 60 insertions(+), 419 deletions(-) (limited to 'xlators/mgmt/glusterd/src/glusterd-volgen.c') diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index 90886dcf3..24a70eb41 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -4107,298 +4107,11 @@ 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 %s format. - * Where 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_brick_stop (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); - 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. + * TODO: Multi-volume delete to be done. + * Cleanup in case of restore failure is pending. * * @param orig_vol volinfo of origin volume * @param snap_vol volinfo of snapshot volume @@ -4409,17 +4122,11 @@ 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,}; + int ret = -1; + glusterd_volinfo_t *new_volinfo = NULL; + glusterd_snap_t *snap = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; this = THIS; GF_ASSERT (this); @@ -4428,154 +4135,88 @@ gd_restore_snap_volume (glusterd_volinfo_t *orig_vol, GF_VALIDATE_OR_GOTO (this->name, orig_vol, out); GF_VALIDATE_OR_GOTO (this->name, snap_vol, out); + snap = snap_vol->snapshot; + GF_VALIDATE_OR_GOTO (this->name, snap, out); - GLUSTERD_GET_VOLUME_DIR (snappath, snap_vol, 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. + /* Snap volume must be stoped before performing the + * restore operation. */ - - /* Backup and restore info file */ - ret = gd_backup_and_restore_snap_files (orig_vol, - orig_vol->shandle->path, - snap_vol->shandle->path); + ret = glusterd_stop_volume (snap_vol); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to restore info " - "file for %s volume", orig_vol->volname); + gf_log (this->name, GF_LOG_ERROR, "Failed to stop " + "snap volume"); goto out; } - GLUSTERD_GET_BRICK_DIR (oldfilename, orig_vol, conf); - GLUSTERD_GET_BRICK_DIR (newfilename, snap_vol, conf); - - /* Backup and restore bricks folder and it's contents */ - ret = gd_backup_and_restore_snap_files (orig_vol, oldfilename, - newfilename); + /* Create a new volinfo for the restored volume */ + ret = glusterd_volinfo_dup (snap_vol, &new_volinfo, _gf_true); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to restore bricks " - "folder for %s volume", orig_vol->volname); + gf_log (this->name, GF_LOG_ERROR, "Failed to create volinfo"); goto out; } - enumerate_transport_reqs (orig_vol->transport_type, types); - + /* Following entries need to be derived from origin volume. */ + strcpy (new_volinfo->volname, orig_vol->volname); + uuid_copy (new_volinfo->volume_id, orig_vol->volume_id); + new_volinfo->snap_count = orig_vol->snap_count; + new_volinfo->snap_max_hard_limit = orig_vol->snap_max_hard_limit; + new_volinfo->is_volume_restored = _gf_true; - 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; - } + /* Copy the snap vol info to the new_volinfo.*/ + ret = glusterd_snap_volinfo_restore (new_volinfo, snap_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to restore snap"); + (void)glusterd_volinfo_delete (new_volinfo); + 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; - } + /* If the orig_vol is already restored then we should delete + * the backend LVMs */ + if (orig_vol->is_volume_restored) { + ret = glusterd_lvm_snapshot_remove (orig_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to remove " + "LVM backend"); + (void)glusterd_volinfo_delete (new_volinfo); + 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. + /* Once the new_volinfo is completely constructed then delete + * the orinal volinfo */ - 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); + ret = glusterd_volinfo_delete (orig_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 " - " trusted client vol file for %s volume", - orig_vol->volname); + gf_log (this->name, GF_LOG_ERROR, "Failed to delete volinfo"); + (void)glusterd_volinfo_delete (new_volinfo); 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; - } + /* New volinfo always shows the status as created. Therefore + * set the status to stop. */ + glusterd_set_volume_status (new_volinfo, GLUSTERD_STATUS_STOPPED); + + list_add_tail (&new_volinfo->vol_list, &conf->volumes); - ret = gd_restore_snap_brick_vol_files (orig_vol, snap_vol); + /* Now delete the snap entry. As a first step delete the snap + * volume information stored in store. */ + ret = glusterd_snap_remove (snap, _gf_false, _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 " - " brick vol files for %s volume", orig_vol->volname); + gf_log (this->name, GF_LOG_WARNING, "Failed to delete " + "snap %s", snap->snapname); 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); + ret = glusterd_store_volinfo (new_volinfo, + GLUSTERD_VOLINFO_VER_AC_INCREMENT); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to update " - "origin volume %s", orig_vol->volname); + gf_log (this->name, GF_LOG_ERROR, "Failed to store volinfo"); 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; - } + ret = 0; out: - return ret; + + return ret; } -- cgit