From f1705e2d338704806cbd90ec9d0d66c0b16cc2ef Mon Sep 17 00:00:00 2001 From: Rajesh Joseph Date: Thu, 5 Jun 2014 10:00:33 +0530 Subject: glusterd/snapshot: Update file-system uuid during snap creation After the brick snapshot file-system UUID of the origin brick and the snapshot brick will be identical. If user is using file-system UUID to mount the backend bricks then this will result in unexpected behaviour. Fix: After taking the LVM snapshot create new UUID for the snapshot brick. Change-Id: I339c90abd72dd392de195b674ea22217e63dfd48 BUG: 1105484 Signed-off-by: Rajesh Joseph Reviewed-on: http://review.gluster.org/8002 Tested-by: Gluster Build System Reviewed-by: Atin Mukherjee Reviewed-by: Krishnan Parthasarathi Tested-by: Krishnan Parthasarathi --- xlators/mgmt/glusterd/src/glusterd-snapshot.c | 212 ++++++++++++++++++++++++++ xlators/mgmt/glusterd/src/glusterd-utils.c | 5 +- xlators/mgmt/glusterd/src/glusterd.h | 1 + 3 files changed, 215 insertions(+), 3 deletions(-) (limited to 'xlators/mgmt/glusterd/src') diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c index 4769b794cd1..456f23abe4b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c @@ -3680,6 +3680,74 @@ out: return ret; } +/* This function will update the backend file-system + * type in origin and snap brickinfo. This will be later + * used to perform file-system specific operation during + * LVM snapshot. + * + * @param orig_brickinfo brickinfo of origin volume + * @param snap_brickinfo brickinfo of snap volume + * + * @return 0 on success and -1 on failure + */ +static int +glusterd_update_fstype (glusterd_brickinfo_t *orig_brickinfo, + glusterd_brickinfo_t *snap_brickinfo) +{ + int32_t ret = -1; + char *mnt_pt = NULL; + char *fstype = NULL; + char buff [PATH_MAX] = ""; + char msg [PATH_MAX] = ""; + char *cmd = NULL; + struct mntent *entry = NULL; + struct mntent save_entry = {0,}; + runner_t runner = {0,}; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (orig_brickinfo); + GF_ASSERT (snap_brickinfo); + + fstype = orig_brickinfo->fstype; + + /* If the file-system type is not set then set the file-system type + * in origin brickinfo */ + if (0 == fstype [0]) { + ret = glusterd_get_brick_root (orig_brickinfo->path, &mnt_pt); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "getting the root " + "of the brick (%s) failed ", + orig_brickinfo->path); + goto out; + } + + entry = glusterd_get_mnt_entry_info (mnt_pt, buff, + sizeof (buff), &save_entry); + if (!entry) { + gf_log (this->name, GF_LOG_ERROR, "getting the mount " + "entry for the brick (%s) failed", + orig_brickinfo->path); + ret = -1; + goto out; + } + + /* Update the origin brickinfo with the backend file-system + * type */ + snprintf (fstype, sizeof (orig_brickinfo->fstype), "%s", + entry->mnt_type); + } + + /* Update the file-system type for snap brickinfo */ + snprintf (snap_brickinfo->fstype, sizeof (snap_brickinfo->fstype), + "%s", fstype); + + ret = 0; +out: + return ret; +} + static int32_t glusterd_add_brick_to_snap_volume (dict_t *dict, dict_t *rsp_dict, glusterd_volinfo_t *snap_vol, @@ -3719,6 +3787,17 @@ glusterd_add_brick_to_snap_volume (dict_t *dict, dict_t *rsp_dict, goto out; } + /* Update the backend file-system type of snap brick in + * snap volinfo. */ + ret = glusterd_update_fstype (original_brickinfo, snap_brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to update " + "file-system type for %s brick", + snap_brickinfo->path); + /* We should not fail snapshot operation if we fail to get + * the file-system type */ + } + snprintf (key, sizeof(key) - 1, "vol%"PRId64".brickdir%d", volcount, brick_count); ret = dict_get_str (dict, key, &snap_brick_dir); @@ -3813,6 +3892,123 @@ out: return ret; } +/* This function will update the file-system UUID of the + * backend snapshot brick. + * + * @param brickinfo brickinfo of the snap volume + * + * @return 0 on success and -1 on failure + */ +static int +glusterd_update_fs_uuid (glusterd_brickinfo_t *brickinfo) +{ + int32_t ret = -1; + char msg [PATH_MAX] = ""; + char uuid_str [NAME_MAX] = ""; + char template [] = "/tmp/xfsmountXXXXXX"; + char *mount_path = NULL; + char *cmd = NULL; + uuid_t uuid = {0,}; + runner_t runner = {0,}; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (brickinfo); + + /* Generate a new UUID */ + uuid_generate (uuid); + + if (NULL == uuid_utoa_r (uuid, uuid_str)) { + gf_log (this->name, GF_LOG_ERROR, "Failed to convert " + "uuid to string for %s brick", brickinfo->path); + goto out; + } + + runinit (&runner); + snprintf (msg, sizeof (msg), "Changing filesystem uuid of %s brick to " + "%s", brickinfo->path, uuid_str); + + /* Call the file-system specific tools to update the file-system + * UUID. Currently we are only supporting xfs and ext2/ext3/ext4 + * file-system. + */ + if (0 == strcmp (brickinfo->fstype, "xfs")) { + /* TODO: xfs_admin tool is used to replace the file-system + * UUID. As of now the tool is failing with error when trying + * to replace the UUID. Therefore as a workaround we mount + * the file-system to a temporary location and then unmount + * it. + * After this xfs_admin tool works fine. + */ + mount_path = mkdtemp (template); + if (NULL == mount_path) { + gf_log (this->name, GF_LOG_ERROR, "Failed to create " + "temporary folder name"); + runner_end (&runner); + goto out; + } + + /* First we mount the brick to a temporary path. Please + * note that we are using "nouuid" option here because + * both the origin volume brick and this brick will have + * the same UUID. And XFS does not allow us to mount a + * file-system which is sharing the UUID with any other + * file-system on the system. + */ + ret = mount (brickinfo->device_path, mount_path, + brickinfo->fstype, 0, "nouuid"); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to mount " + "%s at %s", brickinfo->device_path, + mount_path); + runner_end (&runner); + goto out; + } + + /* Now unmount the brick. */ + ret = glusterd_umount (mount_path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to unmount " + "%s from %s", brickinfo->device_path, + mount_path); + runner_end (&runner); + goto out; + } + + /* Now we are ready to run xfs_admin tool */ + runner_add_args (&runner, "xfs_admin", "-U", uuid_str, + brickinfo->device_path, NULL); + } else if (0 == strcmp (brickinfo->fstype, "ext4") || + 0 == strcmp (brickinfo->fstype, "ext3") || + 0 == strcmp (brickinfo->fstype, "ext2")) { + /* For ext2/ext3/ext4 run tune2fs to change the + * file-system UUID */ + runner_add_args (&runner, "tune2fs", "-U", uuid_str, + brickinfo->device_path, NULL); + } else { + gf_log (this->name, GF_LOG_WARNING, "Changing file-system " + "UUID of %s file-system is not supported as of now", + brickinfo->fstype); + runner_end (&runner); + ret = -1; + goto out; + } + + runner_log (&runner, this->name, GF_LOG_DEBUG, msg); + ret = runner_run (&runner); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to change " + "filesystem uuid of %s brick to %s", + brickinfo->path, uuid_str); + goto out; + } + + ret = 0; +out: + return ret; +} + static int32_t glusterd_take_brick_snapshot (dict_t *dict, glusterd_volinfo_t *snap_vol, glusterd_brickinfo_t *brickinfo, @@ -3852,6 +4048,22 @@ glusterd_take_brick_snapshot (dict_t *dict, glusterd_volinfo_t *snap_vol, goto out; } + /* After the snapshot both the origin brick (LVM brick) and + * the snapshot brick will have the same file-system UUID. This + * will cause lot of problems at mount time. Therefore we must + * generate a new UUID for the snapshot brick + */ + ret = glusterd_update_fs_uuid (brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to update " + "file-system uuid for %s brick", brickinfo->path); + /* Failing to update UUID should not cause snapshot failure. + * Currently UUID is updated only for XFS and ext2/ext3/ext4 + * file-system. + */ + } + + /* create the complete brick here */ ret = glusterd_snap_brick_create (snap_vol, brickinfo, brick_count); if (ret) { diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 3db49d79a23..8515320d894 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -12094,10 +12094,9 @@ glusterd_mount_lvm_snapshot (char *device_path, char *brick_mount_path) runinit (&runner); - snprintf (msg, sizeof (msg), "mount -o nouuid %s %s", + snprintf (msg, sizeof (msg), "mount %s %s", device_path, brick_mount_path); - runner_add_args (&runner, "mount", "-o", "nouuid", device_path, - brick_mount_path, NULL); + runner_add_args (&runner, "mount", device_path, brick_mount_path, NULL); runner_log (&runner, this->name, GF_LOG_DEBUG, msg); ret = runner_run (&runner); if (ret) { diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 1dd823a588f..3da22f62f77 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -191,6 +191,7 @@ struct glusterd_brickinfo { char device_path[PATH_MAX]; char mount_dir[PATH_MAX]; char brick_id[1024];/*Client xlator name, AFR changelog name*/ + char fstype [NAME_MAX]; /* Brick file-system type */ struct list_head brick_list; uuid_t uuid; int port; -- cgit