From 4056ed598f642d2d23a65b79495b0247d84db2f4 Mon Sep 17 00:00:00 2001 From: Avra Sengupta Date: Tue, 6 Jan 2015 07:40:32 +0000 Subject: glusterd: Refactor glusterd-utils.c Refactor glusterd-utils.c to create glusterd-snapshot-utils.c consisting of all snapshot utility functions. Change-Id: Id9823a2aec9b115f9c040c9940f288d4fe753d9b BUG: 1176770 Signed-off-by: Avra Sengupta Reviewed-on: http://review.gluster.org/9391 Reviewed-by: Kaushal M Reviewed-by: Rajesh Joseph Tested-by: Gluster Build System Reviewed-by: Krishnan Parthasarathi Tested-by: Krishnan Parthasarathi --- xlators/mgmt/glusterd/src/Makefile.am | 5 +- xlators/mgmt/glusterd/src/glusterd-handler.c | 1 + xlators/mgmt/glusterd/src/glusterd-handshake.c | 1 + xlators/mgmt/glusterd/src/glusterd-mgmt.c | 1 + xlators/mgmt/glusterd/src/glusterd-op-sm.c | 1 + xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 1 + xlators/mgmt/glusterd/src/glusterd-sm.c | 1 + .../mgmt/glusterd/src/glusterd-snapshot-utils.c | 3704 +++++++++ .../mgmt/glusterd/src/glusterd-snapshot-utils.h | 200 + xlators/mgmt/glusterd/src/glusterd-snapshot.c | 1 + xlators/mgmt/glusterd/src/glusterd-store.c | 1 + xlators/mgmt/glusterd/src/glusterd-syncop.c | 1 + xlators/mgmt/glusterd/src/glusterd-utils.c | 8781 ++++++-------------- xlators/mgmt/glusterd/src/glusterd-utils.h | 220 +- xlators/mgmt/glusterd/src/glusterd-volgen.c | 1 + xlators/mgmt/glusterd/src/glusterd-volume-ops.c | 1 + 16 files changed, 6492 insertions(+), 6429 deletions(-) create mode 100644 xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c create mode 100644 xlators/mgmt/glusterd/src/glusterd-snapshot-utils.h (limited to 'xlators/mgmt/glusterd') diff --git a/xlators/mgmt/glusterd/src/Makefile.am b/xlators/mgmt/glusterd/src/Makefile.am index 950fc17e712..4d14858343e 100644 --- a/xlators/mgmt/glusterd/src/Makefile.am +++ b/xlators/mgmt/glusterd/src/Makefile.am @@ -10,7 +10,8 @@ glusterd_la_SOURCES = glusterd.c glusterd-handler.c glusterd-sm.c \ glusterd-volume-ops.c glusterd-brick-ops.c glusterd-mountbroker.c \ glusterd-syncop.c glusterd-hooks.c glusterd-volume-set.c \ glusterd-locks.c glusterd-snapshot.c glusterd-mgmt-handler.c \ - glusterd-mgmt.c glusterd-peer-utils.c glusterd-statedump.c + glusterd-mgmt.c glusterd-peer-utils.c glusterd-statedump.c \ + glusterd-snapshot-utils.c glusterd_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la \ $(top_builddir)/rpc/xdr/src/libgfxdr.la \ @@ -25,7 +26,7 @@ noinst_HEADERS = glusterd.h glusterd-utils.h glusterd-op-sm.h \ glusterd-pmap.h glusterd-volgen.h glusterd-mountbroker.h \ glusterd-syncop.h glusterd-hooks.h glusterd-locks.h \ glusterd-mgmt.h glusterd-messages.h glusterd-peer-utils.h \ - glusterd-statedump.h + glusterd-statedump.h glusterd-snapshot-utils.h AM_CPPFLAGS = $(GF_CPPFLAGS) -I$(top_srcdir)/libglusterfs/src \ -I$(rpclibdir) -I$(CONTRIBDIR)/rbtree \ diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 0f2c2751883..803a13c8393 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -33,6 +33,7 @@ #include "glusterd-utils.h" #include "glusterd-store.h" #include "glusterd-locks.h" +#include "glusterd-snapshot-utils.h" #include "glusterd1-xdr.h" #include "cli1-xdr.h" diff --git a/xlators/mgmt/glusterd/src/glusterd-handshake.c b/xlators/mgmt/glusterd/src/glusterd-handshake.c index 72e479070b6..e6921c87b89 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handshake.c +++ b/xlators/mgmt/glusterd/src/glusterd-handshake.c @@ -22,6 +22,7 @@ #include "glusterd-utils.h" #include "glusterd-op-sm.h" #include "glusterd-store.h" +#include "glusterd-snapshot-utils.h" #include "glusterfs3.h" #include "protocol-common.h" diff --git a/xlators/mgmt/glusterd/src/glusterd-mgmt.c b/xlators/mgmt/glusterd/src/glusterd-mgmt.c index 0853bd9b4bb..403e13e3678 100644 --- a/xlators/mgmt/glusterd/src/glusterd-mgmt.c +++ b/xlators/mgmt/glusterd/src/glusterd-mgmt.c @@ -21,6 +21,7 @@ #include "glusterd-op-sm.h" #include "glusterd-volgen.h" #include "glusterd-store.h" +#include "glusterd-snapshot-utils.h" extern struct rpc_clnt_program gd_mgmt_v3_prog; diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c index a0cf87598fa..3b5186e4f18 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -43,6 +43,7 @@ #include "cli1-xdr.h" #include "common-utils.h" #include "run.h" +#include "glusterd-snapshot-utils.h" #include #include diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c index ec2d850094a..8f29d26ed24 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c @@ -27,6 +27,7 @@ #include "glusterd-utils.h" #include "common-utils.h" #include "glusterd-messages.h" +#include "glusterd-snapshot-utils.h" #include diff --git a/xlators/mgmt/glusterd/src/glusterd-sm.c b/xlators/mgmt/glusterd/src/glusterd-sm.c index 6b30361e3d5..d3640c0aaa9 100644 --- a/xlators/mgmt/glusterd/src/glusterd-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-sm.c @@ -35,6 +35,7 @@ #include "glusterd-op-sm.h" #include "glusterd-utils.h" #include "glusterd-store.h" +#include "glusterd-snapshot-utils.h" static struct list_head gd_friend_sm_queue; diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c new file mode 100644 index 00000000000..8603e9e950c --- /dev/null +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c @@ -0,0 +1,3704 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif +#include + +#if defined(GF_LINUX_HOST_OS) +#include +#else +#include "mntent_compat.h" +#endif +#include + +#include "dict.h" +#include "syscall.h" +#include "glusterd-op-sm.h" +#include "glusterd-utils.h" +#include "glusterd-store.h" +#include "glusterd-volgen.h" +#include "glusterd-snapshot-utils.h" + +/* + * glusterd_snap_geo_rep_restore: + * This function restores the atime and mtime of marker.tstamp + * if present from snapped marker.tstamp file. + */ +int +glusterd_snap_geo_rep_restore (glusterd_volinfo_t *snap_volinfo, + glusterd_volinfo_t *new_volinfo) +{ + char vol_tstamp_file[PATH_MAX] = {0,}; + char snap_tstamp_file[PATH_MAX] = {0,}; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + int geo_rep_indexing_on = 0; + int ret = 0; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (snap_volinfo); + GF_ASSERT (new_volinfo); + + priv = this->private; + GF_ASSERT (priv); + + /* Check if geo-rep indexing is enabled, if yes, we need restore + * back the mtime of 'marker.tstamp' file. + */ + geo_rep_indexing_on = glusterd_volinfo_get_boolean (new_volinfo, + VKEY_MARKER_XTIME); + if (geo_rep_indexing_on == -1) { + gf_log (this->name, GF_LOG_DEBUG, "Failed" + " to check whether geo-rep-indexing enabled or not"); + ret = 0; + goto out; + } + + if (geo_rep_indexing_on == 1) { + GLUSTERD_GET_VOLUME_DIR (vol_tstamp_file, new_volinfo, priv); + strncat (vol_tstamp_file, "/marker.tstamp", + PATH_MAX - strlen(vol_tstamp_file) - 1); + GLUSTERD_GET_VOLUME_DIR (snap_tstamp_file, snap_volinfo, priv); + strncat (snap_tstamp_file, "/marker.tstamp", + PATH_MAX - strlen(snap_tstamp_file) - 1); + ret = gf_set_timestamp (snap_tstamp_file, vol_tstamp_file); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set atime and mtime of %s as of %s", + vol_tstamp_file, snap_tstamp_file); + goto out; + } + } + +out: + return ret; +} + +/* This function will copy snap volinfo to the new + * passed volinfo and regenerate backend store files + * for the restored snap. + * + * @param new_volinfo new volinfo + * @param snap_volinfo volinfo of snap volume + * + * @return 0 on success and -1 on failure + * + * TODO: Duplicate all members of volinfo, e.g. geo-rep sync slaves + */ +int32_t +glusterd_snap_volinfo_restore (dict_t *dict, dict_t *rsp_dict, + glusterd_volinfo_t *new_volinfo, + glusterd_volinfo_t *snap_volinfo, + int32_t volcount) +{ + char *value = NULL; + char key[PATH_MAX] = ""; + int32_t brick_count = -1; + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_brickinfo_t *new_brickinfo = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (dict); + GF_ASSERT (rsp_dict); + + GF_VALIDATE_OR_GOTO (this->name, new_volinfo, out); + GF_VALIDATE_OR_GOTO (this->name, snap_volinfo, out); + + brick_count = 0; + list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) { + brick_count++; + ret = glusterd_brickinfo_new (&new_brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to create " + "new brickinfo"); + goto out; + } + + /* Duplicate brickinfo */ + ret = glusterd_brickinfo_dup (brickinfo, new_brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to dup " + "brickinfo"); + goto out; + } + + /* Fetch values if present in dict These values won't + * be present in case of a missed restore. In that case + * it's fine to use the local node's value + */ + snprintf (key, sizeof (key), "snap%d.brick%d.path", + volcount, brick_count); + ret = dict_get_str (dict, key, &value); + if (!ret) + strncpy (new_brickinfo->path, value, + sizeof(new_brickinfo->path)); + + snprintf (key, sizeof (key), "snap%d.brick%d.snap_status", + volcount, brick_count); + ret = dict_get_int32 (dict, key, &new_brickinfo->snap_status); + + snprintf (key, sizeof (key), "snap%d.brick%d.device_path", + volcount, brick_count); + ret = dict_get_str (dict, key, &value); + if (!ret) + strncpy (new_brickinfo->device_path, value, + sizeof(new_brickinfo->device_path)); + + snprintf (key, sizeof (key), "snap%d.brick%d.fs_type", + volcount, brick_count); + ret = dict_get_str (dict, key, &value); + if (!ret) + strncpy (new_brickinfo->fstype, value, + sizeof(new_brickinfo->fstype)); + + snprintf (key, sizeof (key), "snap%d.brick%d.mnt_opts", + volcount, brick_count); + ret = dict_get_str (dict, key, &value); + if (!ret) + strncpy (new_brickinfo->mnt_opts, value, + sizeof(new_brickinfo->mnt_opts)); + + /* If the brick is not of this peer, or snapshot is missed * + * for the brick do not replace the xattr for it */ + if ((!uuid_compare (brickinfo->uuid, MY_UUID)) && + (brickinfo->snap_status != -1)) { + /* We need to replace the volume id of all the bricks + * to the volume id of the origin volume. new_volinfo + * has the origin volume's volume id*/ + ret = sys_lsetxattr (new_brickinfo->path, + GF_XATTR_VOL_ID_KEY, + new_volinfo->volume_id, + sizeof (new_volinfo->volume_id), + XATTR_REPLACE); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "set extended attribute %s on %s. " + "Reason: %s, snap: %s", + GF_XATTR_VOL_ID_KEY, + new_brickinfo->path, strerror (errno), + new_volinfo->volname); + goto out; + } + } + + /* If a snapshot is pending for this brick then + * restore should also be pending + */ + if (brickinfo->snap_status == -1) { + /* Adding missed delete to the dict */ + ret = glusterd_add_missed_snaps_to_dict + (rsp_dict, + snap_volinfo, + brickinfo, + brick_count, + GF_SNAP_OPTION_TYPE_RESTORE); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add missed snapshot info " + "for %s:%s in the rsp_dict", + brickinfo->hostname, + brickinfo->path); + goto out; + } + } + + list_add_tail (&new_brickinfo->brick_list, + &new_volinfo->bricks); + /* ownership of new_brickinfo is passed to new_volinfo */ + new_brickinfo = NULL; + } + + /* Regenerate all volfiles */ + ret = glusterd_create_volfiles_and_notify_services (new_volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to regenerate volfiles"); + goto out; + } + + /* Restore geo-rep marker.tstamp's timestamp */ + ret = glusterd_snap_geo_rep_restore (snap_volinfo, new_volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Geo-rep: marker.tstamp's timestamp restoration failed"); + goto out; + } + +out: + if (ret && (NULL != new_brickinfo)) { + (void) glusterd_brickinfo_delete (new_brickinfo); + } + + return ret; +} + +int +glusterd_snap_volinfo_find_by_volume_id (uuid_t volume_id, + glusterd_volinfo_t **volinfo) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_volinfo_t *voliter = NULL; + glusterd_snap_t *snap = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (volinfo); + + if (uuid_is_null(volume_id)) { + gf_log (this->name, GF_LOG_WARNING, "Volume UUID is NULL"); + goto out; + } + + list_for_each_entry (snap, &priv->snapshots, snap_list) { + list_for_each_entry (voliter, &snap->volumes, vol_list) { + if (uuid_compare (volume_id, voliter->volume_id)) + continue; + *volinfo = voliter; + ret = 0; + goto out; + } + } + + gf_log (this->name, GF_LOG_WARNING, "Snap volume not found"); +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +int32_t +glusterd_snap_volinfo_find (char *snap_volname, glusterd_snap_t *snap, + glusterd_volinfo_t **volinfo) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_volinfo_t *snap_vol = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (snap); + GF_ASSERT (snap_volname); + + list_for_each_entry (snap_vol, &snap->volumes, vol_list) { + if (!strcmp (snap_vol->volname, snap_volname)) { + ret = 0; + *volinfo = snap_vol; + goto out; + } + } + + gf_log (this->name, GF_LOG_WARNING, "Snap volume %s not found", + snap_volname); +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +int32_t +glusterd_snap_volinfo_find_from_parent_volname (char *origin_volname, + glusterd_snap_t *snap, + glusterd_volinfo_t **volinfo) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_volinfo_t *snap_vol = NULL; + glusterd_conf_t *priv = NULL; + + this = THIS; + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (snap); + GF_ASSERT (origin_volname); + + list_for_each_entry (snap_vol, &snap->volumes, vol_list) { + if (!strcmp (snap_vol->parent_volname, origin_volname)) { + ret = 0; + *volinfo = snap_vol; + goto out; + } + } + + gf_log (this->name, GF_LOG_DEBUG, "Snap volume not found(snap: %s, " + "origin-volume: %s", snap->snapname, origin_volname); + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* Exports a bricks snapshot details only if required + * + * The details will be exported only if the cluster op-version is greather than + * 4, ie. snapshot is supported in the cluster + */ +int +gd_add_brick_snap_details_to_dict (dict_t *dict, char *prefix, + glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char key[256] = {0,}; + + this = THIS; + GF_ASSERT (this != NULL); + conf = this->private; + GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); + + GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (brickinfo != NULL), out); + + if (conf->op_version < GD_OP_VERSION_3_6_0) { + ret = 0; + goto out; + } + + snprintf (key, sizeof (key), "%s.snap_status", prefix); + ret = dict_set_int32 (dict, key, brickinfo->snap_status); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set snap_status for %s:%s", + brickinfo->hostname, brickinfo->path); + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.device_path", prefix); + ret = dict_set_str (dict, key, brickinfo->device_path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set snap_device for %s:%s", + brickinfo->hostname, brickinfo->path); + goto out; + } + + snprintf (key, sizeof (key), "%s.fs_type", prefix); + ret = dict_set_str (dict, key, brickinfo->fstype); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set fstype for %s:%s", + brickinfo->hostname, brickinfo->path); + goto out; + } + + snprintf (key, sizeof (key), "%s.mnt_opts", prefix); + ret = dict_set_str (dict, key, brickinfo->mnt_opts); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set mnt_opts for %s:%s", + brickinfo->hostname, brickinfo->path); + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.mount_dir", prefix); + ret = dict_set_str (dict, key, brickinfo->mount_dir); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Failed to set mount_dir for %s:%s", + brickinfo->hostname, brickinfo->path); + +out: + return ret; +} + +/* Exports a volumes snapshot details only if required. + * + * The snapshot details will only be exported if the cluster op-version is + * greater than 4, ie. snapshot is supported in the cluster + */ +int +gd_add_vol_snap_details_to_dict (dict_t *dict, char *prefix, + glusterd_volinfo_t *volinfo) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char key[256] = {0,}; + + this = THIS; + GF_ASSERT (this != NULL); + conf = this->private; + GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); + + GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (volinfo != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); + + if (conf->op_version < GD_OP_VERSION_3_6_0) { + ret = 0; + goto out; + } + + snprintf (key, sizeof (key), "%s.restored_from_snap", prefix); + ret = dict_set_dynstr_with_alloc + (dict, key, + uuid_utoa (volinfo->restored_from_snap)); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to set %s for volume" + "%s", key, volinfo->volname); + goto out; + } + + if (strlen (volinfo->parent_volname) > 0) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.parent_volname", prefix); + ret = dict_set_dynstr_with_alloc (dict, key, + volinfo->parent_volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to set %s " + "for volume %s", key, volinfo->volname); + goto out; + } + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.is_snap_volume", prefix); + ret = dict_set_uint32 (dict, key, volinfo->is_snap_volume); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to set %s for volume" + "%s", key, volinfo->volname); + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.snap-max-hard-limit", prefix); + ret = dict_set_uint64 (dict, key, volinfo->snap_max_hard_limit); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to set %s for volume" + "%s", key, volinfo->volname); + } + +out: + return ret; +} + +int32_t +glusterd_add_missed_snaps_to_export_dict (dict_t *peer_data) +{ + char name_buf[PATH_MAX] = ""; + char value[PATH_MAX] = ""; + int32_t missed_snap_count = 0; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + glusterd_missed_snap_info *missed_snapinfo = NULL; + glusterd_snap_op_t *snap_opinfo = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (peer_data); + + priv = this->private; + GF_ASSERT (priv); + + /* Add the missed_entries in the dict */ + list_for_each_entry (missed_snapinfo, &priv->missed_snaps_list, + missed_snaps) { + list_for_each_entry (snap_opinfo, + &missed_snapinfo->snap_ops, + snap_ops_list) { + snprintf (name_buf, sizeof(name_buf), + "missed_snaps_%d", missed_snap_count); + snprintf (value, sizeof(value), "%s:%s=%s:%d:%s:%d:%d", + missed_snapinfo->node_uuid, + missed_snapinfo->snap_uuid, + snap_opinfo->snap_vol_id, + snap_opinfo->brick_num, + snap_opinfo->brick_path, + snap_opinfo->op, + snap_opinfo->status); + + ret = dict_set_dynstr_with_alloc (peer_data, name_buf, + value); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set %s", + name_buf); + goto out; + } + missed_snap_count++; + } + } + + ret = dict_set_int32 (peer_data, "missed_snap_count", + missed_snap_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set missed_snap_count"); + goto out; + } + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +int32_t +glusterd_add_snap_to_dict (glusterd_snap_t *snap, dict_t *peer_data, + int32_t snap_count) +{ + char buf[NAME_MAX] = ""; + char prefix[NAME_MAX] = ""; + int32_t ret = -1; + int32_t volcount = 0; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + gf_boolean_t host_bricks = _gf_false; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (snap); + GF_ASSERT (peer_data); + + snprintf (prefix, sizeof(prefix), "snap%d", snap_count); + + list_for_each_entry (volinfo, &snap->volumes, vol_list) { + volcount++; + ret = glusterd_add_volume_to_dict (volinfo, peer_data, + volcount, prefix); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add snap:%s volume:%s " + "to peer_data dict for handshake", + snap->snapname, volinfo->volname); + goto out; + } + + if (glusterd_is_volume_quota_enabled (volinfo)) { + + ret = glusterd_vol_add_quota_conf_to_dict (volinfo, + peer_data, + volcount, + prefix); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add quota conf for " + "snap:%s volume:%s to peer_data " + "dict for handshake", snap->snapname, + volinfo->volname); + goto out; + } + } + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + if (!uuid_compare (brickinfo->uuid, MY_UUID)) { + host_bricks = _gf_true; + break; + } + } + } + + snprintf (buf, sizeof(buf), "%s.host_bricks", prefix); + ret = dict_set_int8 (peer_data, buf, (int8_t) host_bricks); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set host_bricks for snap %s", + snap->snapname); + goto out; + } + + snprintf (buf, sizeof(buf), "%s.volcount", prefix); + ret = dict_set_int32 (peer_data, buf, volcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set volcount for snap %s", + snap->snapname); + goto out; + } + + snprintf (buf, sizeof(buf), "%s.snapname", prefix); + ret = dict_set_dynstr_with_alloc (peer_data, buf, snap->snapname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set snapname for snap %s", + snap->snapname); + goto out; + } + + snprintf (buf, sizeof(buf), "%s.snap_id", prefix); + ret = dict_set_dynstr_with_alloc (peer_data, buf, + uuid_utoa (snap->snap_id)); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set snap_id for snap %s", + snap->snapname); + goto out; + } + + if (snap->description) { + snprintf (buf, sizeof(buf), "%s.snapid", prefix); + ret = dict_set_dynstr_with_alloc (peer_data, buf, + snap->description); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set description for snap %s", + snap->snapname); + goto out; + } + } + + snprintf (buf, sizeof(buf), "%s.time_stamp", prefix); + ret = dict_set_int64 (peer_data, buf, (int64_t)snap->time_stamp); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set time_stamp for snap %s", + snap->snapname); + goto out; + } + + snprintf (buf, sizeof(buf), "%s.snap_restored", prefix); + ret = dict_set_int8 (peer_data, buf, snap->snap_restored); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set snap_restored for snap %s", + snap->snapname); + goto out; + } + + snprintf (buf, sizeof(buf), "%s.snap_status", prefix); + ret = dict_set_int32 (peer_data, buf, snap->snap_status); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set snap_status for snap %s", + snap->snapname); + goto out; + } +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +int32_t +glusterd_add_snapshots_to_export_dict (dict_t *peer_data) +{ + int32_t snap_count = 0; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + glusterd_snap_t *snap = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (peer_data); + + list_for_each_entry (snap, &priv->snapshots, snap_list) { + snap_count++; + ret = glusterd_add_snap_to_dict (snap, peer_data, snap_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add snap(%s) to the " + " peer_data dict for handshake", + snap->snapname); + goto out; + } + } + + ret = dict_set_int32 (peer_data, "snap_count", snap_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set snap_count"); + goto out; + } + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* Imports the snapshot details of a brick if required and available + * + * Snapshot details will be imported only if the cluster op-verison is >= 4 + */ +int +gd_import_new_brick_snap_details (dict_t *dict, char *prefix, + glusterd_brickinfo_t *brickinfo) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char key[512] = {0,}; + char *snap_device = NULL; + char *fs_type = NULL; + char *mnt_opts = NULL; + char *mount_dir = NULL; + + this = THIS; + GF_ASSERT (this != NULL); + conf = this->private; + GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); + + GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (brickinfo != NULL), out); + + if (conf->op_version < GD_OP_VERSION_3_6_0) { + ret = 0; + goto out; + } + + snprintf (key, sizeof (key), "%s.snap_status", prefix); + ret = dict_get_int32 (dict, key, &brickinfo->snap_status); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.device_path", prefix); + ret = dict_get_str (dict, key, &snap_device); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); + goto out; + } + strcpy (brickinfo->device_path, snap_device); + + snprintf (key, sizeof (key), "%s.fs_type", prefix); + ret = dict_get_str (dict, key, &fs_type); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); + goto out; + } + strcpy (brickinfo->fstype, fs_type); + + snprintf (key, sizeof (key), "%s.mnt_opts", prefix); + ret = dict_get_str (dict, key, &mnt_opts); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); + goto out; + } + strcpy (brickinfo->mnt_opts, mnt_opts); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.mount_dir", prefix); + ret = dict_get_str (dict, key, &mount_dir); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); + goto out; + } + strcpy (brickinfo->mount_dir, mount_dir); + +out: + return ret; +} + +/* + * Imports the snapshot details of a volume if required and available + * + * Snapshot details will be imported only if cluster.op_version is greater than + * or equal to GD_OP_VERSION_3_6_0, the op-version from which volume snapshot is + * supported. + */ +int +gd_import_volume_snap_details (dict_t *dict, glusterd_volinfo_t *volinfo, + char *prefix, char *volname) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char key[256] = {0,}; + char *restored_snap = NULL; + + this = THIS; + GF_ASSERT (this != NULL); + conf = this->private; + GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); + + GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (volinfo != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); + GF_VALIDATE_OR_GOTO (this->name, (volname != NULL), out); + + if (conf->op_version < GD_OP_VERSION_3_6_0) { + ret = 0; + goto out; + } + + snprintf (key, sizeof (key), "%s.is_snap_volume", prefix); + ret = dict_get_uint32 (dict, key, &volinfo->is_snap_volume); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload " + "for %s", key, volname); + goto out; + } + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.restored_from_snap", prefix); + ret = dict_get_str (dict, key, &restored_snap); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload " + "for %s", key, volname); + goto out; + } + + uuid_parse (restored_snap, volinfo->restored_from_snap); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.snap-max-hard-limit", prefix); + ret = dict_get_uint64 (dict, key, + &volinfo->snap_max_hard_limit); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "%s missing in payload " + "for %s", key, volname); +out: + return ret; +} + +int32_t +glusterd_perform_missed_op (glusterd_snap_t *snap, int32_t op) +{ + dict_t *dict = NULL; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *snap_volinfo = NULL; + glusterd_volinfo_t *volinfo = NULL; + glusterd_volinfo_t *tmp = NULL; + xlator_t *this = NULL; + uuid_t null_uuid = {0}; + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (snap); + + dict = dict_new(); + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "Unable to create dict"); + ret = -1; + goto out; + } + + switch (op) { + case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_snap_remove (dict, snap, _gf_true, _gf_false); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to remove snap"); + goto out; + } + + break; + case GF_SNAP_OPTION_TYPE_RESTORE: + list_for_each_entry_safe (snap_volinfo, tmp, + &snap->volumes, vol_list) { + ret = glusterd_volinfo_find + (snap_volinfo->parent_volname, + &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Could not get volinfo of %s", + snap_volinfo->parent_volname); + goto out; + } + + volinfo->version--; + uuid_copy (volinfo->restored_from_snap, null_uuid); + + /* gd_restore_snap_volume() uses the dict and volcount + * to fetch snap brick info from other nodes, which were + * collected during prevalidation. As this is an ad-hoc + * op and only local node's data matter, hence sending + * volcount as 0 and re-using the same dict because we + * need not record any missed creates in the rsp_dict. + */ + ret = gd_restore_snap_volume (dict, dict, volinfo, + snap_volinfo, 0); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to restore snap for %s", + snap->snapname); + volinfo->version++; + goto out; + } + + ret = glusterd_snapshot_restore_cleanup (dict, volinfo, + snap); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to perform snapshot restore " + "cleanup for %s volume", + snap_volinfo->parent_volname); + goto out; + } + } + + break; + default: + /* The entry must be a create, delete, or + * restore entry + */ + gf_log (this->name, GF_LOG_ERROR, "Invalid missed snap entry"); + ret = -1; + goto out; + } + +out: + dict_unref (dict); + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* Perform missed deletes and restores on this node */ +int32_t +glusterd_perform_missed_snap_ops () +{ + int32_t ret = -1; + int32_t op_status = -1; + glusterd_conf_t *priv = NULL; + glusterd_missed_snap_info *missed_snapinfo = NULL; + glusterd_snap_op_t *snap_opinfo = NULL; + glusterd_snap_t *snap = NULL; + uuid_t snap_uuid = {0,}; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + GF_ASSERT (priv); + + list_for_each_entry (missed_snapinfo, &priv->missed_snaps_list, + missed_snaps) { + /* If the pending snap_op is not for this node then continue */ + if (strcmp (missed_snapinfo->node_uuid, uuid_utoa (MY_UUID))) + continue; + + /* Find the snap id */ + uuid_parse (missed_snapinfo->snap_uuid, snap_uuid); + snap = NULL; + snap = glusterd_find_snap_by_id (snap_uuid); + if (!snap) { + /* If the snap is not found, then a delete or a + * restore can't be pending on that snap_uuid. + */ + gf_log (this->name, GF_LOG_DEBUG, + "Not a pending delete or restore op"); + continue; + } + + op_status = GD_MISSED_SNAP_PENDING; + list_for_each_entry (snap_opinfo, &missed_snapinfo->snap_ops, + snap_ops_list) { + /* If the snap_op is create or its status is + * GD_MISSED_SNAP_DONE then continue + */ + if ((snap_opinfo->status == GD_MISSED_SNAP_DONE) || + (snap_opinfo->op == GF_SNAP_OPTION_TYPE_CREATE)) + continue; + + /* Perform the actual op for the first time for + * this snap, and mark the snap_status as + * GD_MISSED_SNAP_DONE. For other entries for the same + * snap, just mark the entry as done. + */ + if (op_status == GD_MISSED_SNAP_PENDING) { + ret = glusterd_perform_missed_op + (snap, + snap_opinfo->op); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to perform missed snap op"); + goto out; + } + op_status = GD_MISSED_SNAP_DONE; + } + + snap_opinfo->status = GD_MISSED_SNAP_DONE; + } + } + + ret = 0; +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* Import friend volumes missed_snap_list and update * + * missed_snap_list if need be */ +int32_t +glusterd_import_friend_missed_snap_list (dict_t *peer_data) +{ + int32_t missed_snap_count = -1; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (peer_data); + + priv = this->private; + GF_ASSERT (priv); + + /* Add the friends missed_snaps entries to the in-memory list */ + ret = dict_get_int32 (peer_data, "missed_snap_count", + &missed_snap_count); + if (ret) { + gf_log (this->name, GF_LOG_INFO, + "No missed snaps"); + ret = 0; + goto out; + } + + ret = glusterd_add_missed_snaps_to_list (peer_data, + missed_snap_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to add missed snaps to list"); + goto out; + } + + ret = glusterd_perform_missed_snap_ops (); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to perform snap operations"); + /* Not going to out at this point coz some * + * missed ops might have been performed. We * + * need to persist the current list * + */ + } + + ret = glusterd_store_update_missed_snaps (); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to update missed_snaps_list"); + goto out; + } + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* Check for the peer_snap_name in the list of existing snapshots. + * If a snap exists with the same name and a different snap_id, then + * there is a conflict. Set conflict as _gf_true, and snap to the + * conflicting snap object. If a snap exists with the same name, and the + * same snap_id, then there is no conflict. Set conflict as _gf_false + * and snap to the existing snap object. If no snap exists with the + * peer_snap_name, then there is no conflict. Set conflict as _gf_false + * and snap to NULL. + */ +void +glusterd_is_peer_snap_conflicting (char *peer_snap_name, char *peer_snap_id, + gf_boolean_t *conflict, + glusterd_snap_t **snap, char *hostname) +{ + uuid_t peer_snap_uuid = {0,}; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (peer_snap_name); + GF_ASSERT (peer_snap_id); + GF_ASSERT (conflict); + GF_ASSERT (snap); + GF_ASSERT (hostname); + + *snap = glusterd_find_snap_by_name (peer_snap_name); + if (*snap) { + uuid_parse (peer_snap_id, peer_snap_uuid); + if (!uuid_compare (peer_snap_uuid, (*snap)->snap_id)) { + /* Current node contains the same snap having + * the same snapname and snap_id + */ + gf_log (this->name, GF_LOG_DEBUG, + "Snapshot %s from peer %s present in " + "localhost", peer_snap_name, hostname); + *conflict = _gf_false; + } else { + /* Current node contains the same snap having + * the same snapname but different snap_id + */ + gf_log (this->name, GF_LOG_DEBUG, + "Snapshot %s from peer %s conflicts with " + "snapshot in localhost", peer_snap_name, + hostname); + *conflict = _gf_true; + } + } else { + /* Peer contains snapshots missing on the current node */ + gf_log (this->name, GF_LOG_INFO, + "Snapshot %s from peer %s missing on localhost", + peer_snap_name, hostname); + *conflict = _gf_false; + } +} + +/* Check if the local node is hosting any bricks for the given snapshot */ +gf_boolean_t +glusterd_are_snap_bricks_local (glusterd_snap_t *snap) +{ + gf_boolean_t is_local = _gf_false; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (snap); + + list_for_each_entry (volinfo, &snap->volumes, vol_list) { + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + if (!uuid_compare (brickinfo->uuid, MY_UUID)) { + is_local = _gf_true; + goto out; + } + } + } + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", is_local); + return is_local; +} + +/* Check if the peer has missed any snap delete + * or restore for the given snap_id + */ +gf_boolean_t +glusterd_peer_has_missed_snap_delete (glusterd_peerinfo_t *peerinfo, + char *peer_snap_id) +{ + char *peer_uuid = NULL; + gf_boolean_t missed_delete = _gf_false; + glusterd_conf_t *priv = NULL; + glusterd_missed_snap_info *missed_snapinfo = NULL; + glusterd_snap_op_t *snap_opinfo = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (peerinfo); + GF_ASSERT (peer_snap_id); + + peer_uuid = uuid_utoa (peerinfo->uuid); + + list_for_each_entry (missed_snapinfo, &priv->missed_snaps_list, + missed_snaps) { + /* Look for missed snap for the same peer, and + * the same snap_id + */ + if ((!strcmp (peer_uuid, missed_snapinfo->node_uuid)) && + (!strcmp (peer_snap_id, missed_snapinfo->snap_uuid))) { + /* Check if the missed snap's op is delete and the + * status is pending + */ + list_for_each_entry (snap_opinfo, + &missed_snapinfo->snap_ops, + snap_ops_list) { + if (((snap_opinfo->op == + GF_SNAP_OPTION_TYPE_DELETE) || + (snap_opinfo->op == + GF_SNAP_OPTION_TYPE_RESTORE)) && + (snap_opinfo->status == + GD_MISSED_SNAP_PENDING)) { + missed_delete = _gf_true; + goto out; + } + } + } + } + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", missed_delete); + return missed_delete; +} + +/* Genrate and store snap volfiles for imported snap object */ +int32_t +glusterd_gen_snap_volfiles (glusterd_volinfo_t *snap_vol, char *peer_snap_name) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_volinfo_t *parent_volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (snap_vol); + GF_ASSERT (peer_snap_name); + + ret = glusterd_store_volinfo (snap_vol, GLUSTERD_VOLINFO_VER_AC_NONE); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to store snapshot " + "volinfo (%s) for snap %s", snap_vol->volname, + peer_snap_name); + goto out; + } + + ret = generate_brick_volfiles (snap_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "generating the brick volfiles for the " + "snap %s failed", peer_snap_name); + goto out; + } + + ret = generate_client_volfiles (snap_vol, GF_CLIENT_TRUSTED); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "generating the trusted client volfiles for " + "the snap %s failed", peer_snap_name); + goto out; + } + + ret = generate_client_volfiles (snap_vol, GF_CLIENT_OTHER); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "generating the client volfiles for the " + "snap %s failed", peer_snap_name); + goto out; + } + + ret = glusterd_volinfo_find (snap_vol->parent_volname, + &parent_volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Parent volinfo " + "not found for %s volume of snap %s", + snap_vol->volname, peer_snap_name); + goto out; + } + + glusterd_list_add_snapvol (parent_volinfo, snap_vol); + + snap_vol->status = GLUSTERD_STATUS_STARTED; + + ret = glusterd_store_volinfo (snap_vol, GLUSTERD_VOLINFO_VER_AC_NONE); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to store snap volinfo"); + goto out; + } +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* Import snapshot info from peer_data and add it to priv */ +int32_t +glusterd_import_friend_snap (dict_t *peer_data, int32_t snap_count, + char *peer_snap_name, char *peer_snap_id) +{ + char buf[NAME_MAX] = ""; + char prefix[NAME_MAX] = ""; + dict_t *dict = NULL; + glusterd_snap_t *snap = NULL; + glusterd_volinfo_t *snap_vol = NULL; + glusterd_conf_t *priv = NULL; + int32_t ret = -1; + int32_t volcount = -1; + int32_t i = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (peer_data); + GF_ASSERT (peer_snap_name); + GF_ASSERT (peer_snap_id); + + snprintf (prefix, sizeof(prefix), "snap%d", snap_count); + + snap = glusterd_new_snap_object (); + if (!snap) { + gf_log (this->name, GF_LOG_ERROR, "Could not create " + "the snap object for snap %s", peer_snap_name); + goto out; + } + + dict = dict_new (); + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to create dict"); + ret = -1; + goto out; + } + + strcpy (snap->snapname, peer_snap_name); + uuid_parse (peer_snap_id, snap->snap_id); + + snprintf (buf, sizeof(buf), "%s.snapid", prefix); + ret = dict_get_str (peer_data, buf, &snap->description); + + snprintf (buf, sizeof(buf), "%s.time_stamp", prefix); + ret = dict_get_int64 (peer_data, buf, &snap->time_stamp); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to get time_stamp for snap %s", + peer_snap_name); + goto out; + } + + snprintf (buf, sizeof(buf), "%s.snap_restored", prefix); + ret = dict_get_int8 (peer_data, buf, (int8_t *) &snap->snap_restored); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to get snap_restored for snap %s", + peer_snap_name); + goto out; + } + + snprintf (buf, sizeof(buf), "%s.snap_status", prefix); + ret = dict_get_int32 (peer_data, buf, (int32_t *) &snap->snap_status); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to get snap_status for snap %s", + peer_snap_name); + goto out; + } + + /* If the snap is scheduled to be decommissioned, then + * don't accept the snap */ + if (snap->snap_status == GD_SNAP_STATUS_DECOMMISSION) { + gf_log (this->name, GF_LOG_DEBUG, + "The snap(%s) is scheduled to be decommissioned " + "Not accepting the snap.", peer_snap_name); + glusterd_snap_remove (dict, snap, + _gf_true, _gf_true); + ret = 0; + goto out; + } + + snprintf (buf, sizeof(buf), "%s.volcount", prefix); + ret = dict_get_int32 (peer_data, buf, &volcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to get volcount for snap %s", + peer_snap_name); + goto out; + } + + ret = glusterd_store_create_snap_dir (snap); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "Failed to create snap dir"); + goto out; + } + + list_add_order (&snap->snap_list, &priv->snapshots, + glusterd_compare_snap_time); + + for (i = 1; i <= volcount; i++) { + ret = glusterd_import_volinfo (peer_data, i, + &snap_vol, prefix); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to import snap volinfo for " + "snap %s", peer_snap_name); + goto out; + } + + snap_vol->snapshot = snap; + + ret = glusterd_gen_snap_volfiles (snap_vol, peer_snap_name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to generate snap vol files " + "for snap %s", peer_snap_name); + goto out; + } + + ret = glusterd_import_quota_conf (peer_data, i, + snap_vol, prefix); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to import quota conf " + "for snap %s", peer_snap_name); + goto out; + } + + snap_vol = NULL; + } + + ret = glusterd_store_snap (snap); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Could not store snap" + "object %s", peer_snap_name); + goto out; + } + +out: + if (ret) + glusterd_snap_remove (dict, snap, + _gf_true, _gf_true); + + if (dict) + dict_unref (dict); + + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* During a peer-handshake, after the volumes have synced, and the list of + * missed snapshots have synced, the node will perform the pending deletes + * and restores on this list. At this point, the current snapshot list in + * the node will be updated, and hence in case of conflicts arising during + * snapshot handshake, the peer hosting the bricks will be given precedence + * Likewise, if there will be a conflict, and both peers will be in the same + * state, i.e either both would be hosting bricks or both would not be hosting + * bricks, then a decision can't be taken and a peer-reject will happen. + * + * glusterd_compare_and_update_snap() implements the following algorithm to + * perform the above task: + * Step 1: Start. + * Step 2: Check if the peer is missing a delete or restore on the said snap. + * If yes, goto step 6. + * Step 3: Check if there is a conflict between the peer's data and the + * local snap. If no, goto step 5. + * Step 4: As there is a conflict, check if both the peer and the local nodes + * are hosting bricks. Based on the results perform the following: + * Peer Hosts Bricks Local Node Hosts Bricks Action + * Yes Yes Goto Step 7 + * No No Goto Step 7 + * Yes No Goto Step 8 + * No Yes Goto Step 6 + * Step 5: Check if the local node is missing the peer's data. + * If yes, goto step 9. + * Step 6: It's a no-op. Goto step 10 + * Step 7: Peer Reject. Goto step 10 + * Step 8: Delete local node's data. + * Step 9: Accept Peer Data. + * Step 10: Stop + * + */ +int32_t +glusterd_compare_and_update_snap (dict_t *peer_data, int32_t snap_count, + glusterd_peerinfo_t *peerinfo) +{ + char buf[NAME_MAX] = ""; + char prefix[NAME_MAX] = ""; + char *peer_snap_name = NULL; + char *peer_snap_id = NULL; + dict_t *dict = NULL; + glusterd_snap_t *snap = NULL; + gf_boolean_t conflict = _gf_false; + gf_boolean_t is_local = _gf_false; + gf_boolean_t is_hosted = _gf_false; + gf_boolean_t missed_delete = _gf_false; + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (peer_data); + GF_ASSERT (peerinfo); + + snprintf (prefix, sizeof(prefix), "snap%d", snap_count); + + /* Fetch the peer's snapname */ + snprintf (buf, sizeof(buf), "%s.snapname", prefix); + ret = dict_get_str (peer_data, buf, &peer_snap_name); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to fetch snapname from peer: %s", + peerinfo->hostname); + goto out; + } + + /* Fetch the peer's snap_id */ + snprintf (buf, sizeof(buf), "%s.snap_id", prefix); + ret = dict_get_str (peer_data, buf, &peer_snap_id); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to fetch snap_id from peer: %s", + peerinfo->hostname); + goto out; + } + + /* Check if the peer has missed a snap delete or restore + * resulting in stale data for the snap in question + */ + missed_delete = glusterd_peer_has_missed_snap_delete (peerinfo, + peer_snap_id); + if (missed_delete == _gf_true) { + /* Peer has missed delete on the missing/conflicting snap_id */ + gf_log (this->name, GF_LOG_INFO, "Peer %s has missed a delete " + "on snap %s", peerinfo->hostname, peer_snap_name); + ret = 0; + goto out; + } + + /* Check if there is a conflict, and if the + * peer data is already present + */ + glusterd_is_peer_snap_conflicting (peer_snap_name, peer_snap_id, + &conflict, &snap, + peerinfo->hostname); + if (conflict == _gf_false) { + if (snap) { + /* Peer has snap with the same snapname + * and snap_id. No need to accept peer data + */ + ret = 0; + goto out; + } else { + /* Peer has snap with the same snapname + * and snap_id, which local node doesn't have. + */ + goto accept_peer_data; + } + } + + /* There is a conflict. Check if the current node is + * hosting bricks for the conflicted snap. + */ + is_local = glusterd_are_snap_bricks_local (snap); + + /* Check if the peer is hosting any bricks for the + * conflicting snap + */ + snprintf (buf, sizeof(buf), "%s.host_bricks", prefix); + ret = dict_get_int8 (peer_data, buf, (int8_t *) &is_hosted); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to fetch host_bricks from peer: %s " + "for %s", peerinfo->hostname, peer_snap_name); + goto out; + } + + /* As there is a conflict at this point of time, the data of the + * node that hosts a brick takes precedence. If both the local + * node and the peer are in the same state, i.e if both of them + * are either hosting or not hosting the bricks, for the snap, + * then it's a peer reject + */ + if (is_hosted == is_local) { + gf_log (this->name, GF_LOG_ERROR, + "Conflict in snapshot %s with peer %s", + peer_snap_name, peerinfo->hostname); + ret = -1; + goto out; + } + + if (is_hosted == _gf_false) { + /* If there was a conflict, and the peer is not hosting + * any brick, then don't accept peer data + */ + gf_log (this->name, GF_LOG_DEBUG, + "Peer doesn't hosts bricks for conflicting " + "snap(%s). Not accepting peer data.", + peer_snap_name); + ret = 0; + goto out; + } + + /* The peer is hosting a brick in case of conflict + * And local node isn't. Hence remove local node's + * data and accept peer data + */ + + gf_log (this->name, GF_LOG_DEBUG, "Peer hosts bricks for conflicting " + "snap(%s). Removing local data. Accepting peer data.", + peer_snap_name); + + dict = dict_new(); + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to create dict"); + ret = -1; + goto out; + } + + ret = glusterd_snap_remove (dict, snap, _gf_true, _gf_false); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to remove snap %s", snap->snapname); + goto out; + } + +accept_peer_data: + + /* Accept Peer Data */ + ret = glusterd_import_friend_snap (peer_data, snap_count, + peer_snap_name, peer_snap_id); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to import snap %s from peer %s", + peer_snap_name, peerinfo->hostname); + goto out; + } + +out: + if (dict) + dict_unref (dict); + + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +/* Compare snapshots present in peer_data, with the snapshots in + * the current node + */ +int32_t +glusterd_compare_friend_snapshots (dict_t *peer_data, + glusterd_peerinfo_t *peerinfo) +{ + int32_t ret = -1; + int32_t snap_count = 0; + int i = 1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (peer_data); + GF_ASSERT (peerinfo); + + ret = dict_get_int32 (peer_data, "snap_count", &snap_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to fetch snap_count"); + goto out; + } + + for (i = 1; i <= snap_count; i++) { + /* Compare one snapshot from peer_data at a time */ + ret = glusterd_compare_and_update_snap (peer_data, i, peerinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to compare snapshots with peer %s", + peerinfo->hostname); + goto out; + } + } + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +struct rpc_clnt* +glusterd_snapd_get_rpc (glusterd_volinfo_t *volinfo) +{ + return volinfo->snapd.rpc; +} + +int32_t +glusterd_add_snapd_to_dict (glusterd_volinfo_t *volinfo, + dict_t *dict, int32_t count) +{ + + int ret = -1; + int32_t pid = -1; + int32_t brick_online = -1; + char key[1024] = {0}; + char base_key[1024] = {0}; + char pidfile[PATH_MAX] = {0}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + + GF_ASSERT (volinfo); + GF_ASSERT (dict); + + this = THIS; + GF_ASSERT (this); + + priv = this->private; + + snprintf (base_key, sizeof (base_key), "brick%d", count); + snprintf (key, sizeof (key), "%s.hostname", base_key); + ret = dict_set_str (dict, key, "Snapshot Daemon"); + if (ret) + goto out; + + snprintf (key, sizeof (key), "%s.path", base_key); + ret = dict_set_dynstr (dict, key, gf_strdup (uuid_utoa (MY_UUID))); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.port", base_key); + ret = dict_set_int32 (dict, key, volinfo->snapd.port); + if (ret) + goto out; + + glusterd_get_snapd_pidfile (volinfo, pidfile, sizeof (pidfile)); + + brick_online = gf_is_service_running (pidfile, &pid); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pid", base_key); + ret = dict_set_int32 (dict, key, pid); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.status", base_key); + ret = dict_set_int32 (dict, key, brick_online); + +out: + if (ret) + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); + + return ret; +} + +int +glusterd_snap_config_use_rsp_dict (dict_t *dst, dict_t *src) +{ + char buf[PATH_MAX] = ""; + char *volname = NULL; + int ret = -1; + int config_command = 0; + uint64_t i = 0; + uint64_t hard_limit = GLUSTERD_SNAPS_MAX_HARD_LIMIT; + uint64_t soft_limit = GLUSTERD_SNAPS_DEF_SOFT_LIMIT_PERCENT; + uint64_t value = 0; + uint64_t voldisplaycount = 0; + + if (!dst || !src) { + gf_log ("", GF_LOG_ERROR, "Source or Destination " + "dict is empty."); + goto out; + } + + ret = dict_get_int32 (dst, "config-command", &config_command); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "failed to get config-command type"); + goto out; + } + + switch (config_command) { + case GF_SNAP_CONFIG_DISPLAY: + ret = dict_get_uint64 (src, + GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, + &hard_limit); + if (!ret) { + ret = dict_set_uint64 (dst, + GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, + hard_limit); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set snap_max_hard_limit"); + goto out; + } + } else { + /* Received dummy response from other nodes */ + ret = 0; + goto out; + } + + ret = dict_get_uint64 (src, + GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT, + &soft_limit); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get snap_max_soft_limit"); + goto out; + } + + ret = dict_set_uint64 (dst, + GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT, + soft_limit); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set snap_max_soft_limit"); + goto out; + } + + ret = dict_get_uint64 (src, "voldisplaycount", + &voldisplaycount); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get voldisplaycount"); + goto out; + } + + ret = dict_set_uint64 (dst, "voldisplaycount", + voldisplaycount); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set voldisplaycount"); + goto out; + } + + for (i = 0; i < voldisplaycount; i++) { + snprintf (buf, sizeof(buf), + "volume%"PRIu64"-volname", i); + ret = dict_get_str (src, buf, &volname); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get %s", buf); + goto out; + } + ret = dict_set_str (dst, buf, volname); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set %s", buf); + goto out; + } + + snprintf (buf, sizeof(buf), + "volume%"PRIu64"-snap-max-hard-limit", i); + ret = dict_get_uint64 (src, buf, &value); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get %s", buf); + goto out; + } + ret = dict_set_uint64 (dst, buf, value); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set %s", buf); + goto out; + } + + snprintf (buf, sizeof(buf), + "volume%"PRIu64"-active-hard-limit", i); + ret = dict_get_uint64 (src, buf, &value); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get %s", buf); + goto out; + } + ret = dict_set_uint64 (dst, buf, value); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set %s", buf); + goto out; + } + + snprintf (buf, sizeof(buf), + "volume%"PRIu64"-snap-max-soft-limit", i); + ret = dict_get_uint64 (src, buf, &value); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get %s", buf); + goto out; + } + ret = dict_set_uint64 (dst, buf, value); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set %s", buf); + goto out; + } + } + + break; + default: + break; + } + + ret = 0; +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +glusterd_merge_brick_status (dict_t *dst, dict_t *src) +{ + int64_t volume_count = 0; + int64_t index = 0; + int64_t j = 0; + int64_t brick_count = 0; + int64_t brick_order = 0; + char key[PATH_MAX] = {0, }; + char snapbrckcnt[PATH_MAX] = {0, }; + char snapbrckord[PATH_MAX] = {0, }; + int ret = -1; + int32_t brick_online = 0; + xlator_t *this = NULL; + int32_t snap_command = 0; + + this = THIS; + GF_ASSERT (this); + + if (!dst || !src) { + gf_log (this->name, GF_LOG_ERROR, "Source or Destination " + "dict is empty."); + goto out; + } + + ret = dict_get_int32 (dst, "type", &snap_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " + "the snapshot command"); + goto out; + } + + if (snap_command == GF_SNAP_OPTION_TYPE_DELETE) { + gf_log (this->name, GF_LOG_DEBUG, "snapshot delete command." + " Need not merge the status of the bricks"); + ret = 0; + goto out; + } + + ret = dict_get_int64 (src, "volcount", &volume_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the volume count"); + goto out; + } + + for (index = 0; index < volume_count; index++) { + ret = snprintf (snapbrckcnt, sizeof(snapbrckcnt) - 1, + "snap-vol%"PRId64"_brickcount", index+1); + ret = dict_get_int64 (src, snapbrckcnt, &brick_count); + if (ret) { + gf_log (this->name, GF_LOG_TRACE, + "No bricks for this volume in this dict (%s)", + snapbrckcnt); + continue; + } + + for (j = 0; j < brick_count; j++) { + /* Fetching data from source dict */ + snprintf (snapbrckord, sizeof(snapbrckord) - 1, + "snap-vol%"PRId64".brick%"PRId64".order", + index+1, j); + + ret = dict_get_int64 (src, snapbrckord, &brick_order); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to get brick order (%s)", + snapbrckord); + goto out; + } + + snprintf (key, sizeof (key) - 1, + "snap-vol%"PRId64".brick%"PRId64".status", + index+1, brick_order); + ret = dict_get_int32 (src, key, &brick_online); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the brick status (%s)", key); + goto out; + } + + ret = dict_set_int32 (dst, key, brick_online); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "set the brick status (%s)", key); + goto out; + } + brick_online = 0; + } + } + + ret = 0; + +out: + return ret; +} + +/* Aggregate missed_snap_counts from different nodes and save it * + * in the req_dict of the originator node */ +int +glusterd_snap_create_use_rsp_dict (dict_t *dst, dict_t *src) +{ + char *buf = NULL; + char *tmp_str = NULL; + char name_buf[PATH_MAX] = ""; + int32_t i = -1; + int32_t ret = -1; + int32_t src_missed_snap_count = -1; + int32_t dst_missed_snap_count = -1; + xlator_t *this = NULL; + int8_t soft_limit_flag = -1; + + this = THIS; + GF_ASSERT (this); + + if (!dst || !src) { + gf_log (this->name, GF_LOG_ERROR, "Source or Destination " + "dict is empty."); + goto out; + } + + ret = glusterd_merge_brick_status (dst, src); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to merge brick " + "status"); + goto out; + } + + ret = dict_get_str (src, "snapuuid", &buf); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to get snap UUID"); + goto out; + } + + ret = dict_set_dynstr_with_alloc (dst, "snapuuid", buf); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set snap uuid in dict"); + goto out; + } + + /* set in dst dictionary soft-limit-reach only if soft-limit-reach + * is present src dictionary */ + ret = dict_get_int8 (src, "soft-limit-reach", &soft_limit_flag); + if (!ret) { + ret = dict_set_int8 (dst, "soft-limit-reach", soft_limit_flag); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set " + "soft_limit_flag"); + goto out; + } + } + + ret = dict_get_int32 (src, "missed_snap_count", + &src_missed_snap_count); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "No missed snaps"); + ret = 0; + goto out; + } + + ret = dict_get_int32 (dst, "missed_snap_count", + &dst_missed_snap_count); + if (ret) { + /* Initialize dst_missed_count for the first time */ + dst_missed_snap_count = 0; + } + + for (i = 0; i < src_missed_snap_count; i++) { + snprintf (name_buf, sizeof(name_buf), "missed_snaps_%d", i); + ret = dict_get_str (src, name_buf, &buf); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to fetch %s", name_buf); + goto out; + } + + snprintf (name_buf, sizeof(name_buf), "missed_snaps_%d", + dst_missed_snap_count); + + tmp_str = gf_strdup (buf); + if (!tmp_str) { + ret = -1; + goto out; + } + + ret = dict_set_dynstr (dst, name_buf, tmp_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set %s", name_buf); + goto out; + } + + tmp_str = NULL; + dst_missed_snap_count++; + } + + ret = dict_set_int32 (dst, "missed_snap_count", dst_missed_snap_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Unable to set dst_missed_snap_count"); + goto out; + } + +out: + if (ret && tmp_str) + GF_FREE(tmp_str); + + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +int +glusterd_snap_use_rsp_dict (dict_t *dst, dict_t *src) +{ + int ret = -1; + int32_t snap_command = 0; + + if (!dst || !src) { + gf_log ("", GF_LOG_ERROR, "Source or Destination " + "dict is empty."); + goto out; + } + + ret = dict_get_int32 (dst, "type", &snap_command); + if (ret) { + gf_log ("", GF_LOG_ERROR, "unable to get the type of " + "the snapshot command"); + goto out; + } + + switch (snap_command) { + case GF_SNAP_OPTION_TYPE_CREATE: + case GF_SNAP_OPTION_TYPE_DELETE: + ret = glusterd_snap_create_use_rsp_dict (dst, src); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to use rsp dict"); + goto out; + } + break; + case GF_SNAP_OPTION_TYPE_CONFIG: + ret = glusterd_snap_config_use_rsp_dict (dst, src); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to use rsp dict"); + goto out; + } + break; + default: + /* copy the response dictinary's contents to the dict to be + * sent back to the cli */ + dict_copy (src, dst); + break; + } + + ret = 0; +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +glusterd_compare_snap_time(struct list_head *list1, struct list_head *list2) +{ + glusterd_snap_t *snap1 = NULL; + glusterd_snap_t *snap2 = NULL; + double diff_time = 0; + + GF_ASSERT (list1); + GF_ASSERT (list2); + + snap1 = list_entry(list1, glusterd_snap_t, snap_list); + snap2 = list_entry(list2, glusterd_snap_t, snap_list); + diff_time = difftime(snap1->time_stamp, snap2->time_stamp); + + return (int)diff_time; +} + +int +glusterd_compare_snap_vol_time(struct list_head *list1, struct list_head *list2) +{ + glusterd_volinfo_t *snapvol1 = NULL; + glusterd_volinfo_t *snapvol2 = NULL; + double diff_time = 0; + + GF_ASSERT (list1); + GF_ASSERT (list2); + + snapvol1 = list_entry(list1, glusterd_volinfo_t, snapvol_list); + snapvol2 = list_entry(list2, glusterd_volinfo_t, snapvol_list); + diff_time = difftime(snapvol1->snapshot->time_stamp, + snapvol2->snapshot->time_stamp); + + return (int)diff_time; +} + +int32_t +glusterd_missed_snapinfo_new (glusterd_missed_snap_info **missed_snapinfo) +{ + glusterd_missed_snap_info *new_missed_snapinfo = NULL; + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (missed_snapinfo); + + new_missed_snapinfo = GF_CALLOC (1, sizeof(*new_missed_snapinfo), + gf_gld_mt_missed_snapinfo_t); + + if (!new_missed_snapinfo) + goto out; + + INIT_LIST_HEAD (&new_missed_snapinfo->missed_snaps); + INIT_LIST_HEAD (&new_missed_snapinfo->snap_ops); + + *missed_snapinfo = new_missed_snapinfo; + + ret = 0; + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +int32_t +glusterd_missed_snap_op_new (glusterd_snap_op_t **snap_op) +{ + glusterd_snap_op_t *new_snap_op = NULL; + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (snap_op); + + new_snap_op = GF_CALLOC (1, sizeof(*new_snap_op), + gf_gld_mt_missed_snapinfo_t); + + if (!new_snap_op) + goto out; + + new_snap_op->brick_num = -1; + new_snap_op->op = -1; + new_snap_op->status = -1; + INIT_LIST_HEAD (&new_snap_op->snap_ops_list); + + *snap_op = new_snap_op; + + ret = 0; +out: + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + return ret; +} + +gf_boolean_t +mntopts_exists (const char *str, const char *opts) +{ + char *dup_val = NULL; + char *savetok = NULL; + char *token = NULL; + gf_boolean_t exists = _gf_false; + + GF_ASSERT (opts); + + if (!str || !strlen(str)) + goto out; + + dup_val = gf_strdup (str); + if (!dup_val) + goto out; + + token = strtok_r (dup_val, ",", &savetok); + while (token) { + if (!strcmp (token, opts)) { + exists = _gf_true; + goto out; + } + token = strtok_r (NULL, ",", &savetok); + } + +out: + GF_FREE (dup_val); + return exists; +} + +int32_t +glusterd_mount_lvm_snapshot (glusterd_brickinfo_t *brickinfo, + char *brick_mount_path) +{ + char msg[NAME_MAX] = ""; + char mnt_opts[1024] = ""; + int32_t ret = -1; + runner_t runner = {0, }; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (brick_mount_path); + GF_ASSERT (brickinfo); + + + runinit (&runner); + snprintf (msg, sizeof (msg), "mount %s %s", + brickinfo->device_path, brick_mount_path); + + strcpy (mnt_opts, brickinfo->mnt_opts); + + /* XFS file-system does not allow to mount file-system with duplicate + * UUID. File-system UUID of snapshot and its origin volume is same. + * Therefore to mount such a snapshot in XFS we need to pass nouuid + * option + */ + if (!strcmp (brickinfo->fstype, "xfs") && + !mntopts_exists (mnt_opts, "nouuid")) { + if (strlen (mnt_opts) > 0) + strcat (mnt_opts, ","); + strcat (mnt_opts, "nouuid"); + } + + + if (strlen (mnt_opts) > 0) { + runner_add_args (&runner, "mount", "-o", mnt_opts, + brickinfo->device_path, brick_mount_path, NULL); + } else { + runner_add_args (&runner, "mount", brickinfo->device_path, + brick_mount_path, NULL); + } + + runner_log (&runner, this->name, GF_LOG_DEBUG, msg); + ret = runner_run (&runner); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "mounting the snapshot " + "logical device %s failed (error: %s)", + brickinfo->device_path, strerror (errno)); + goto out; + } else + gf_log (this->name, GF_LOG_DEBUG, "mounting the snapshot " + "logical device %s successful", brickinfo->device_path); + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning with %d", ret); + return ret; +} + +gf_boolean_t +glusterd_volume_quorum_calculate (glusterd_volinfo_t *volinfo, dict_t *dict, + int down_count, gf_boolean_t first_brick_on, + int8_t snap_force, int quorum_count, + char *quorum_type, char **op_errstr) +{ + gf_boolean_t quorum_met = _gf_false; + char err_str[PATH_MAX] = {0, }; + xlator_t *this = NULL; + int up_count = 0; + + this = THIS; + GF_ASSERT (this); + + if (!volinfo || !dict) { + gf_log (this->name, GF_LOG_WARNING, "input parameters NULL"); + goto out; + } + + if (!snap_force && down_count) { + snprintf (err_str, sizeof (err_str), "One or more bricks may " + "be down. Use the force option "); + gf_log (this->name, GF_LOG_ERROR, "%s", err_str); + *op_errstr = gf_strdup (err_str); + goto out; + } + + up_count = volinfo->dist_leaf_count - down_count; + + if (quorum_type && !strcmp (quorum_type, "fixed")) { + if (up_count >= quorum_count) { + quorum_met = _gf_true; + goto out; + } + } else { + if ((GF_CLUSTER_TYPE_DISPERSE != volinfo->type) && + (volinfo->dist_leaf_count % 2 == 0)) { + if ((up_count > quorum_count) || + ((up_count == quorum_count) && first_brick_on)) { + quorum_met = _gf_true; + goto out; + } + } else { + if (up_count >= quorum_count) { + quorum_met = _gf_true; + goto out; + } + } + } + + if (!quorum_met) { + snprintf (err_str, sizeof (err_str), "quorum is not met"); + gf_log (this->name, GF_LOG_WARNING, "%s", err_str); + *op_errstr = gf_strdup (err_str); + } + +out: + return quorum_met; +} + +int32_t +glusterd_volume_quorum_check (glusterd_volinfo_t *volinfo, int64_t index, + dict_t *dict, char *key_prefix, + int8_t snap_force, int quorum_count, + char *quorum_type, char **op_errstr) +{ + int ret = 0; + xlator_t *this = NULL; + int64_t i = 0; + int64_t j = 0; + char key[1024] = {0, }; + int down_count = 0; + gf_boolean_t first_brick_on = _gf_true; + glusterd_conf_t *priv = NULL; + gf_boolean_t quorum_met = _gf_false; + int distribute_subvols = 0; + int32_t brick_online = 0; + char err_str[PATH_MAX] = {0, }; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + if (!volinfo || !dict) { + gf_log (this->name, GF_LOG_WARNING, "input parameters NULL"); + goto out; + } + + if ((!glusterd_is_volume_replicate (volinfo) || + volinfo->replica_count < 3) && + (GF_CLUSTER_TYPE_DISPERSE != volinfo->type)) { + for (i = 0; i < volinfo->brick_count ; i++) { + /* for a pure distribute volume, and replica volume + with replica count 2, quorum is not met if even + one of its subvolumes is down + */ + snprintf (key, sizeof (key), + "%s%"PRId64".brick%"PRId64".status", + key_prefix, index, i); + ret = dict_get_int32 (dict, key, &brick_online); + if (ret || !brick_online) { + ret = 1; + snprintf (err_str, sizeof (err_str), "quorum " + "is not met"); + gf_log (this->name, GF_LOG_ERROR, "%s", + err_str); + *op_errstr = gf_strdup (err_str); + goto out; + } + } + ret = 0; + quorum_met = _gf_true; + } else { + distribute_subvols = volinfo->brick_count / + volinfo->dist_leaf_count; + for (j = 0; j < distribute_subvols; j++) { + /* by default assume quorum is not met + TODO: Handle distributed striped replicate volumes + Currently only distributed replicate volumes are + handled. + */ + ret = 1; + quorum_met = _gf_false; + for (i = 0; i < volinfo->dist_leaf_count; i++) { + snprintf (key, sizeof (key), + "%s%"PRId64".brick%"PRId64".status", + key_prefix, index, + (j * volinfo->dist_leaf_count) + i); + ret = dict_get_int32 (dict, key, &brick_online); + if (ret || !brick_online) { + if (i == 0) + first_brick_on = _gf_false; + down_count++; + } + } + + quorum_met = glusterd_volume_quorum_calculate (volinfo, + dict, + down_count, + first_brick_on, + snap_force, + quorum_count, + quorum_type, + op_errstr); + /* goto out if quorum is not met */ + if (!quorum_met) { + ret = -1; + goto out; + } + + down_count = 0; + first_brick_on = _gf_true; + } + } + + if (quorum_met) { + gf_log (this->name, GF_LOG_DEBUG, "volume %s is in quorum", + volinfo->volname); + ret = 0; + } + +out: + return ret; +} + +int32_t +glusterd_snap_quorum_check_for_create (dict_t *dict, gf_boolean_t snap_volume, + char **op_errstr, + struct list_head *peers_list) +{ + int8_t snap_force = 0; + int32_t force = 0; + char err_str[PATH_MAX] = {0, }; + int quorum_count = 0; + char *quorum_type = NULL; + int32_t tmp = 0; + char key_prefix[PATH_MAX] = {0, }; + char *snapname = NULL; + glusterd_snap_t *snap = NULL; + glusterd_volinfo_t *volinfo = NULL; + char *volname = NULL; + int64_t volcount = 0; + char key[PATH_MAX] = {0, }; + int64_t i = 0; + int32_t ret = -1; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "dict is NULL"); + goto out; + } + + if (snap_volume) { + ret = dict_get_str (dict, "snapname", &snapname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get snapname"); + goto out; + } + + snap = glusterd_find_snap_by_name (snapname); + if (!snap) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get the snapshot %s", snapname); + ret = -1; + goto out; + } + } + + ret = dict_get_int32 (dict, "flags", &force); + if (!ret && (force & GF_CLI_FLAG_OP_FORCE)) + snap_force = 1; + if (!snap_force) { + /* Do a quorum check of glusterds also. Because, + the missed snapshot information will be saved + by glusterd and if glusterds are not in + quorum, then better fail the snapshot + */ + if (!does_gd_meet_server_quorum (this, peers_list, _gf_true)) { + snprintf (err_str, sizeof (err_str), + "glusterds are not in quorum"); + gf_log (this->name, GF_LOG_WARNING, "%s", + err_str); + *op_errstr = gf_strdup (err_str); + ret = -1; + goto out; + } + + gf_log (this->name, GF_LOG_DEBUG, "glusterds are in " + "quorum"); + } + + ret = dict_get_int64 (dict, "volcount", &volcount); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to get " + "volcount"); + goto out; + } + + for (i = 1; i <= volcount; i++) { + snprintf (key, sizeof (key), "%s%"PRId64, + snap_volume?"snap-volname":"volname", i); + ret = dict_get_str (dict, key, &volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "get volname"); + goto out; + } + + if (snap_volume) { + ret = glusterd_snap_volinfo_find (volname, snap, + &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to get snap volume %s " + "for snap %s", volname, + snapname); + goto out; + } + } else { + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "failed to find the volume %s", + volname); + goto out; + } + } + + /* for replicate volumes with replica count equal to or + greater than 3, do quorum check by getting what type + of quorum rule has been set by getting the volume + option set. If getting the option fails, then assume + default. + AFR does this: + if quorum type is "auto": + - for odd numner of bricks (n), n/2 + 1 + bricks should be present + - for even number of bricks n, n/2 bricks + should be present along with the 1st + subvolume + if quorum type is not "auto": + - get the quorum count from dict with the + help of the option "cluster.quorum-count" + if the option is not there in the dict, + then assume quorum type is auto and follow + the above method. + For non replicate volumes quorum is met only if all + the bricks of the volume are online + */ + + if (GF_CLUSTER_TYPE_REPLICATE == volinfo->type) { + if (volinfo->replica_count % 2 == 0) + quorum_count = volinfo->replica_count/2; + else + quorum_count = + volinfo->replica_count/2 + 1; + } else if (GF_CLUSTER_TYPE_DISPERSE == volinfo->type) { + quorum_count = volinfo->disperse_count - + volinfo->redundancy_count; + } else { + quorum_count = volinfo->brick_count; + } + + ret = dict_get_str (volinfo->dict, + "cluster.quorum-type", + &quorum_type); + if (!ret && !strcmp (quorum_type, "fixed")) { + ret = dict_get_int32 (volinfo->dict, + "cluster.quorum-count", + &tmp); + /* if quorum-type option is not found in the + dict assume auto quorum type. i.e n/2 + 1. + The same assumption is made when quorum-count + option cannot be obtained from the dict (even + if the quorum-type option is not set to auto, + the behavior is set to the default behavior) + */ + if (!ret) { + /* for dispersed volumes, only allow quorums + equal or larger than minimum functional + value. + */ + if ((GF_CLUSTER_TYPE_DISPERSE != + volinfo->type) || + (tmp >= quorum_count)) { + quorum_count = tmp; + } else { + gf_log(this->name, GF_LOG_INFO, + "Ignoring small quorum-count " + "(%d) on dispersed volume", tmp); + quorum_type = NULL; + } + } else + quorum_type = NULL; + } + + snprintf (key_prefix, sizeof (key_prefix), + "%s", snap_volume?"snap-vol":"vol"); + + ret = glusterd_volume_quorum_check (volinfo, i, dict, + key_prefix, + snap_force, + quorum_count, + quorum_type, + op_errstr); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "volume %s " + "is not in quorum", volinfo->volname); + goto out; + } + } +out: + return ret; +} + +int32_t +glusterd_snap_quorum_check (dict_t *dict, gf_boolean_t snap_volume, + char **op_errstr, + struct list_head *peers_list) +{ + int32_t ret = -1; + xlator_t *this = NULL; + int32_t snap_command = 0; + char err_str[PATH_MAX] = {0, }; + + this = THIS; + GF_ASSERT (this); + + if (!dict) { + gf_log (this->name, GF_LOG_ERROR, "dict is NULL"); + goto out; + } + + + ret = dict_get_int32 (dict, "type", &snap_command); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " + "the snapshot command"); + goto out; + } + + switch (snap_command) { + case GF_SNAP_OPTION_TYPE_CREATE: + ret = glusterd_snap_quorum_check_for_create (dict, snap_volume, + op_errstr, + peers_list); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "Quorum check" + "failed during snapshot create command"); + goto out; + } + break; + case GF_SNAP_OPTION_TYPE_DELETE: + case GF_SNAP_OPTION_TYPE_RESTORE: + if (!does_gd_meet_server_quorum (this, peers_list, _gf_true)) { + ret = -1; + snprintf (err_str, sizeof (err_str), + "glusterds are not in quorum"); + gf_log (this->name, GF_LOG_WARNING, "%s", + err_str); + *op_errstr = gf_strdup (err_str); + goto out; + } + + gf_log (this->name, GF_LOG_DEBUG, "glusterds are in " + "quorum"); + break; + default: + break; + } + + ret = 0; + +out: + return ret; +} + +int32_t +glusterd_umount (const char *path) +{ + char msg[NAME_MAX] = ""; + int32_t ret = -1; + runner_t runner = {0, }; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (path); + + runinit (&runner); + snprintf (msg, sizeof (msg), "umount path %s", path); + runner_add_args (&runner, _PATH_UMOUNT, "-f", path, NULL); + runner_log (&runner, this->name, GF_LOG_DEBUG, msg); + ret = runner_run (&runner); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "umounting %s failed (%s)", + path, strerror (errno)); + + gf_log (this->name, GF_LOG_TRACE, "Returning with %d", ret); + return ret; +} + +int32_t +glusterd_copy_file (const char *source, const char *destination) +{ + int32_t ret = -1; + xlator_t *this = NULL; + char buffer[1024] = ""; + int src_fd = -1; + int dest_fd = -1; + int read_len = -1; + struct stat stbuf = {0,}; + mode_t dest_mode = 0; + + this = THIS; + GF_ASSERT (this); + + GF_ASSERT (source); + GF_ASSERT (destination); + + /* Here is stat is made to get the file permission of source file*/ + ret = lstat (source, &stbuf); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "%s not found", source); + goto out; + } + + dest_mode = stbuf.st_mode & 0777; + + src_fd = open (source, O_RDONLY); + if (src_fd < 0) { + ret = -1; + gf_log (this->name, GF_LOG_ERROR, "Unable to open file %s", + source); + goto out; + } + + dest_fd = open (destination, O_CREAT | O_RDWR, dest_mode); + if (dest_fd < 0) { + ret = -1; + gf_log (this->name, GF_LOG_ERROR, + "Unble to open a file %s", destination); + goto out; + } + + do { + ret = read (src_fd, buffer, sizeof (buffer)); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "Error reading file " + "%s", source); + goto out; + } + read_len = ret; + if (read_len == 0) + break; + + ret = write (dest_fd, buffer, read_len); + if (ret != read_len) { + gf_log (this->name, GF_LOG_ERROR, "Error writing in " + "file %s", destination); + goto out; + } + } while (ret > 0); +out: + if (src_fd > 0) + close (src_fd); + + if (dest_fd > 0) + close (dest_fd); + return ret; +} + +int32_t +glusterd_copy_folder (const char *source, const char *destination) +{ + DIR *dir_ptr = NULL; + struct dirent *direntp = NULL; + int32_t ret = -1; + char src_path[PATH_MAX] = ""; + char dest_path[PATH_MAX] = ""; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + GF_ASSERT (source); + GF_ASSERT (destination); + + dir_ptr = opendir (source); + if (!dir_ptr) { + gf_log (this->name, GF_LOG_ERROR, "Unable to open %s", source); + goto out; + } + + while ((direntp = readdir (dir_ptr)) != NULL) { + if (strcmp (direntp->d_name, ".") == 0 || + strcmp (direntp->d_name, "..") == 0) + continue; + ret = snprintf (src_path, sizeof (src_path), "%s/%s", + source, direntp->d_name); + if (ret < 0) + goto out; + + ret = snprintf (dest_path, sizeof (dest_path), "%s/%s", + destination, direntp->d_name); + if (ret < 0) + goto out; + + ret = glusterd_copy_file (src_path, dest_path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Could not copy " + "%s to %s", src_path, dest_path); + goto out; + } + } +out: + if (dir_ptr) + closedir (dir_ptr); + + return ret; +} + +int32_t +glusterd_get_geo_rep_session (char *slave_key, char *origin_volname, + dict_t *gsync_slaves_dict, char *session, + char *slave) +{ + int32_t ret = -1; + char *token = NULL; + char *temp = NULL; + char *ip = NULL; + char *buffer = NULL; + xlator_t *this = NULL; + char *slave_temp = NULL; + char *save_ptr = NULL; + + this = THIS; + GF_ASSERT (this); + + GF_ASSERT (slave_key); + GF_ASSERT (origin_volname); + GF_ASSERT (gsync_slaves_dict); + + ret = dict_get_str (gsync_slaves_dict, slave_key, &buffer); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "get value for key %s", slave_key); + goto out; + } + + temp = gf_strdup (buffer); + if (!temp) { + ret = -1; + goto out; + } + + token = strtok_r (temp, "/", &save_ptr); + + token = strtok_r (NULL, ":", &save_ptr); + if (!token) { + ret = -1; + goto out; + } + token++; + + ip = gf_strdup (token); + if (!ip) { + ret = -1; + goto out; + } + + token = strtok_r (NULL, "\0", &save_ptr); + if (!token) { + ret = -1; + goto out; + } + token++; + + slave_temp = gf_strdup (token); + if (!slave) { + ret = -1; + goto out; + } + + ret = snprintf (session, PATH_MAX, "%s_%s_%s", + origin_volname, ip, slave_temp); + if (ret < 0) /* Negative value is an error */ + goto out; + + ret = snprintf (slave, PATH_MAX, "%s::%s", ip, slave_temp); + if (ret < 0) { + goto out; + } + + ret = 0; /* Success */ + +out: + if (temp) + GF_FREE (temp); + + if (ip) + GF_FREE (ip); + + if (slave_temp) + GF_FREE (slave_temp); + + return ret; +} + +int32_t +glusterd_copy_quota_files (glusterd_volinfo_t *src_vol, + glusterd_volinfo_t *dest_vol) { + + int32_t ret = -1; + char src_dir[PATH_MAX] = ""; + char dest_dir[PATH_MAX] = ""; + char src_path[PATH_MAX] = ""; + char dest_path[PATH_MAX] = ""; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + struct stat stbuf = {0,}; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + GF_ASSERT (src_vol); + GF_ASSERT (dest_vol); + + GLUSTERD_GET_VOLUME_DIR (src_dir, src_vol, priv); + + GLUSTERD_GET_VOLUME_DIR (dest_dir, dest_vol, priv); + + ret = snprintf (src_path, sizeof (src_path), "%s/quota.conf", + src_dir); + if (ret < 0) + goto out; + + /* quota.conf is not present if quota is not enabled, Hence ignoring + * the absence of this file + */ + ret = lstat (src_path, &stbuf); + if (ret) { + ret = 0; + gf_log (this->name, GF_LOG_DEBUG, "%s not found", src_path); + goto out; + } + + ret = snprintf (dest_path, sizeof (dest_path), "%s/quota.conf", + dest_dir); + if (ret < 0) + goto out; + + ret = glusterd_copy_file (src_path, dest_path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to copy %s in %s", + src_path, dest_path); + goto out; + } + + ret = snprintf (src_path, sizeof (src_path), "%s/quota.cksum", + src_dir); + if (ret < 0) + goto out; + + /* If quota.conf is present and quota.cksum is not present, then + * that scenario is considered as invalid, hence error out. + */ + ret = lstat (src_path, &stbuf); + if (ret) { + ret = -1; + gf_log (this->name, GF_LOG_ERROR, "%s not found", src_path); + goto out; + } + + ret = snprintf (dest_path, sizeof (dest_path), "%s/quota.cksum", + dest_dir); + if (ret < 0) + goto out; + + ret = glusterd_copy_file (src_path, dest_path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to copy %s in %s", + src_path, dest_path); + goto out; + } + +out: + return ret; + +} + +int32_t +glusterd_restore_geo_rep_files (glusterd_volinfo_t *snap_vol) +{ + int32_t ret = -1; + char src_path[PATH_MAX] = ""; + char dest_path[PATH_MAX] = ""; + xlator_t *this = NULL; + char *origin_volname = NULL; + glusterd_volinfo_t *origin_vol = NULL; + int i = 0; + char key[PATH_MAX] = ""; + char session[PATH_MAX] = ""; + char slave[PATH_MAX] = ""; + char snapgeo_dir[PATH_MAX] = ""; + glusterd_conf_t *priv = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + GF_ASSERT (snap_vol); + + origin_volname = gf_strdup (snap_vol->parent_volname); + if (!origin_volname) { + ret = -1; + goto out; + } + + ret = glusterd_volinfo_find (origin_volname, &origin_vol); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to fetch " + "volinfo for volname %s", origin_volname); + goto out; + } + + for (i = 1 ; i <= snap_vol->gsync_slaves->count; i++) { + ret = snprintf (key, sizeof (key), "slave%d", i); + if (ret < 0) { + goto out; + } + + /* "origin_vol" is used here because geo-replication saves + * the session in the form of master_ip_slave. + * As we need the master volume to be same even after + * restore, we are passing the origin volume name. + * + * "snap_vol->gsync_slaves" contain the slave information + * when the snapshot was taken, hence we have to restore all + * those slaves information when we do snapshot restore. + */ + ret = glusterd_get_geo_rep_session (key, origin_vol->volname, + snap_vol->gsync_slaves, + session, slave); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to get geo-rep session"); + goto out; + } + + GLUSTERD_GET_SNAP_GEO_REP_DIR(snapgeo_dir, snap_vol->snapshot, + priv); + ret = snprintf (src_path, sizeof (src_path), + "%s/%s", snapgeo_dir, session); + if (ret < 0) + goto out; + + ret = snprintf (dest_path, sizeof (dest_path), + "%s/%s/%s", priv->workdir, GEOREP, + session); + if (ret < 0) + goto out; + + ret = glusterd_copy_folder (src_path, dest_path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Could not copy " + "%s to %s", src_path, dest_path); + goto out; + } + } +out: + if (origin_volname) + GF_ASSERT (origin_volname); + + return ret; +} + +/* Snapd functions */ +int +glusterd_is_snapd_enabled (glusterd_volinfo_t *volinfo) +{ + int ret = 0; + xlator_t *this = THIS; + + ret = dict_get_str_boolean (volinfo->dict, "features.uss", -2); + if (ret == -2) { + gf_log (this->name, GF_LOG_DEBUG, "Key features.uss not " + "present in the dict for volume %s", volinfo->volname); + ret = 0; + + } else if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get 'features.uss'" + " from dict for volume %s", volinfo->volname); + } + + return ret; +} + +void +glusterd_get_snapd_rundir (glusterd_volinfo_t *volinfo, + char *path, int path_len) +{ + char workdir[PATH_MAX] = {0,}; + glusterd_conf_t *priv = THIS->private; + + GLUSTERD_GET_VOLUME_DIR (workdir, volinfo, priv); + + snprintf (path, path_len, "%s/run", workdir); +} + +void +glusterd_get_snapd_volfile (glusterd_volinfo_t *volinfo, + char *path, int path_len) +{ + char workdir[PATH_MAX] = {0,}; + glusterd_conf_t *priv = THIS->private; + + GLUSTERD_GET_VOLUME_DIR (workdir, volinfo, priv); + + snprintf (path, path_len, "%s/%s-snapd.vol", workdir, + volinfo->volname); +} + +void +glusterd_get_snapd_pidfile (glusterd_volinfo_t *volinfo, + char *path, int path_len) +{ + char rundir[PATH_MAX] = {0,}; + + glusterd_get_snapd_rundir (volinfo, rundir, sizeof (rundir)); + + snprintf (path, path_len, "%s/%s-snapd.pid", rundir, volinfo->volname); +} + +void +glusterd_set_snapd_socket_filepath (glusterd_volinfo_t *volinfo, + char *path, int path_len) +{ + char sockfilepath[PATH_MAX] = {0,}; + char rundir[PATH_MAX] = {0,}; + + glusterd_get_snapd_rundir (volinfo, rundir, sizeof (rundir)); + snprintf (sockfilepath, sizeof (sockfilepath), "%s/run-%s", + rundir, uuid_utoa (MY_UUID)); + + glusterd_set_socket_filepath (sockfilepath, path, path_len); +} + +gf_boolean_t +glusterd_is_snapd_running (glusterd_volinfo_t *volinfo) +{ + char pidfile[PATH_MAX] = {0,}; + int pid = -1; + glusterd_conf_t *priv = THIS->private; + + glusterd_get_snapd_pidfile (volinfo, pidfile, + sizeof (pidfile)); + + return gf_is_service_running (pidfile, &pid); +} + +int +glusterd_restart_snapds (glusterd_conf_t *priv) +{ + glusterd_volinfo_t *volinfo = NULL; + int ret = 0; + xlator_t *this = THIS; + + list_for_each_entry (volinfo, &priv->volumes, vol_list) { + if (volinfo->status == GLUSTERD_STATUS_STARTED && + glusterd_is_snapd_enabled (volinfo)) { + ret = glusterd_snapd_start (volinfo, + _gf_false); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Couldn't start snapd for " + "vol: %s", volinfo->volname); + goto out; + } + } + } +out: + return ret; +} + +gf_boolean_t +glusterd_is_snapd_online (glusterd_volinfo_t *volinfo) +{ + return volinfo->snapd.online; +} + +void +glusterd_snapd_set_online_status (glusterd_volinfo_t *volinfo, + gf_boolean_t status) +{ + volinfo->snapd.online = status; +} + +static inline void +glusterd_snapd_set_rpc (glusterd_volinfo_t *volinfo, struct rpc_clnt *rpc) +{ + volinfo->snapd.rpc = rpc; +} + +int32_t +glusterd_snapd_connect (glusterd_volinfo_t *volinfo, char *socketpath) +{ + int ret = 0; + dict_t *options = NULL; + struct rpc_clnt *rpc = NULL; + glusterd_conf_t *priv = THIS->private; + + rpc = glusterd_snapd_get_rpc (volinfo); + + if (rpc == NULL) { + /* Setting frame-timeout to 10mins (600seconds). + * Unix domain sockets ensures that the connection is reliable. + * The default timeout of 30mins used for unreliable network + * connections is too long for unix domain socket connections. + */ + ret = rpc_transport_unix_options_build (&options, socketpath, + 600); + if (ret) + goto out; + + ret = dict_set_str(options, + "transport.socket.ignore-enoent", "on"); + if (ret) + goto out; + + glusterd_volinfo_ref (volinfo); + + synclock_unlock (&priv->big_lock); + ret = glusterd_rpc_create (&rpc, options, + glusterd_snapd_rpc_notify, + volinfo); + synclock_lock (&priv->big_lock); + if (ret) + goto out; + + (void) glusterd_snapd_set_rpc (volinfo, rpc); + } +out: + return ret; +} + +int32_t +glusterd_snapd_disconnect (glusterd_volinfo_t *volinfo) +{ + struct rpc_clnt *rpc = NULL; + glusterd_conf_t *priv = THIS->private; + + rpc = glusterd_snapd_get_rpc (volinfo); + + (void) glusterd_snapd_set_rpc (volinfo, NULL); + + if (rpc) + glusterd_rpc_clnt_unref (priv, rpc); + + return 0; +} + +int32_t +glusterd_snapd_start (glusterd_volinfo_t *volinfo, gf_boolean_t wait) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + runner_t runner = {0,}; + char pidfile[PATH_MAX] = {0,}; + char logfile[PATH_MAX] = {0,}; + char logdir[PATH_MAX] = {0,}; + char volfile[PATH_MAX] = {0,}; + char glusterd_uuid[1024] = {0,}; + char rundir[PATH_MAX] = {0,}; + char sockfpath[PATH_MAX] = {0,}; + char volfileid[256] = {0}; + char *volfileserver = NULL; + char valgrind_logfile[PATH_MAX] = {0}; + int snapd_port = 0; + char *volname = volinfo->volname; + char snapd_id[PATH_MAX] = {0,}; + char msg[1024] = {0,}; + + this = THIS; + GF_ASSERT(this); + + if (glusterd_is_snapd_running (volinfo)) { + ret = 0; + goto connect; + } + + priv = this->private; + + glusterd_get_snapd_rundir (volinfo, rundir, sizeof (rundir)); + ret = mkdir (rundir, 0777); + + if ((ret == -1) && (EEXIST != errno)) { + gf_log (this->name, GF_LOG_ERROR, "Unable to create rundir %s", + rundir); + goto out; + } + + glusterd_get_snapd_pidfile (volinfo, pidfile, sizeof (pidfile)); + glusterd_get_snapd_volfile (volinfo, volfile, sizeof (volfile)); + + ret = sys_access (volfile, F_OK); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, + "snapd Volfile %s is not present", volfile); + + /* If glusterd is down on one of the nodes and during + * that time "USS is enabled" for the first time. After some + * time when the glusterd which was down comes back it tries + * to look for the snapd volfile and it does not find snapd + * volfile and because of this starting of snapd fails. + * Therefore, if volfile is not present then create a fresh + * volfile. + */ + ret = glusterd_create_snapd_volfile (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Couldn't create " + "snapd volfile for volume: %s", + volinfo->volname); + goto out; + } + } + + snprintf (logdir, PATH_MAX, "%s/snaps/%s", + DEFAULT_LOG_FILE_DIRECTORY, volname); + ret = mkdir_p (logdir, 0755, _gf_true); + if ((ret == -1) && (EEXIST != errno)) { + gf_log (this->name, GF_LOG_ERROR, "Unable to create logdir %s", + logdir); + goto out; + } + + snprintf (logfile, PATH_MAX, "%s/snapd.log", logdir); + + snprintf (volfileid, sizeof (volfileid), "snapd/%s", volname); + glusterd_set_snapd_socket_filepath (volinfo, sockfpath, + sizeof (sockfpath)); + + if (dict_get_str (this->options, "transport.socket.bind-address", + &volfileserver) != 0) { + volfileserver = "localhost"; + } + + runinit (&runner); + + if (priv->valgrind) { + snprintf (valgrind_logfile, PATH_MAX, "%s/valgrind-snapd.log", + logdir); + + runner_add_args (&runner, "valgrind", "--leak-check=full", + "--trace-children=yes", "--track-origins=yes", + NULL); + runner_argprintf (&runner, "--log-file=%s", valgrind_logfile); + } + + snprintf (snapd_id, sizeof (snapd_id), "snapd-%s", volname); + runner_add_args (&runner, SBIN_DIR"/glusterfsd", + "-s", volfileserver, + "--volfile-id", volfileid, + "-p", pidfile, + "-l", logfile, + "--brick-name", snapd_id, + "-S", sockfpath, NULL); + + snapd_port = volinfo->snapd.port; + if (!snapd_port) { + snapd_port = pmap_registry_alloc (THIS); + if (!snapd_port) { + snprintf (msg, sizeof (msg), "Could not allocate port " + "for snapd service for volume %s", volname); + + runner_log (&runner, this->name, GF_LOG_DEBUG, msg); + ret = -1; + goto out; + } + } + + runner_add_arg (&runner, "--brick-port"); + runner_argprintf (&runner, "%d", snapd_port); + runner_add_arg (&runner, "--xlator-option"); + runner_argprintf (&runner, "%s-server.listen-port=%d", + volname, snapd_port); + + snprintf (msg, sizeof (msg), + "Starting the snapd service for volume %s", volname); + runner_log (&runner, this->name, GF_LOG_DEBUG, msg); + + if (!wait) { + ret = runner_run_nowait (&runner); + } else { + synclock_unlock (&priv->big_lock); + { + ret = runner_run (&runner); + } + synclock_lock (&priv->big_lock); + } + + volinfo->snapd.port = snapd_port; + +connect: + if (ret == 0) + glusterd_snapd_connect (volinfo, sockfpath); + +out: + return ret; +} + +int +glusterd_snapd_stop (glusterd_volinfo_t *volinfo) +{ + char pidfile[PATH_MAX] = {0,}; + char sockfpath[PATH_MAX] = {0,}; + glusterd_conf_t *priv = THIS->private; + int ret = 0; + + (void)glusterd_snapd_disconnect (volinfo); + + if (!glusterd_is_snapd_running (volinfo)) + goto out; + + glusterd_get_snapd_pidfile (volinfo, pidfile, sizeof (pidfile)); + ret = glusterd_service_stop ("snapd", pidfile, SIGTERM, _gf_true); + + if (ret == 0) { + glusterd_set_snapd_socket_filepath (volinfo, sockfpath, + sizeof (sockfpath)); + (void)glusterd_unlink_file (sockfpath); + } +out: + return ret; +} + +int +glusterd_handle_snapd_option (glusterd_volinfo_t *volinfo) +{ + int ret = 0; + xlator_t *this = THIS; + + if (volinfo->is_snap_volume) + return 0; + + ret = glusterd_is_snapd_enabled (volinfo); + if (ret == -1) { + gf_log (this->name, GF_LOG_ERROR, "Failed to read volume " + "options"); + goto out; + } + + if (ret) { + if (!glusterd_is_volume_started (volinfo)) { + if (glusterd_is_snapd_running (volinfo)) { + ret = glusterd_snapd_stop (volinfo); + if (ret) + gf_log (this->name, GF_LOG_ERROR, + "Couldn't stop snapd for " + "volume: %s", + volinfo->volname); + } else { + /* Since snapd is not running set ret to 0 */ + ret = 0; + } + goto out; + } + + ret = glusterd_create_snapd_volfile (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Couldn't create " + "snapd volfile for volume: %s", + volinfo->volname); + goto out; + } + + ret = glusterd_snapd_start (volinfo, _gf_false); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Couldn't start " + "snapd for volume: %s", volinfo->volname); + goto out; + } + + } else if (glusterd_is_snapd_running (volinfo)) { + ret = glusterd_snapd_stop (volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Couldn't stop snapd for volume: %s", + volinfo->volname); + goto out; + } + volinfo->snapd.port = 0; + } + +out: + return ret; +} + +int32_t +glusterd_is_snap_soft_limit_reached (glusterd_volinfo_t *volinfo, dict_t *dict) +{ + int32_t ret = -1; + uint64_t opt_max_hard = GLUSTERD_SNAPS_MAX_HARD_LIMIT; + uint64_t opt_max_soft = GLUSTERD_SNAPS_DEF_SOFT_LIMIT_PERCENT; + uint64_t limit = 0; + int auto_delete = 0; + uint64_t effective_max_limit = 0; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + GF_ASSERT (volinfo); + GF_ASSERT (dict); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + /* config values snap-max-hard-limit and snap-max-soft-limit are + * optional and hence we are not erroring out if values are not + * present + */ + gd_get_snap_conf_values_if_present (priv->opts, &opt_max_hard, + &opt_max_soft); + + /* "auto-delete" might not be set by user explicitly, + * in that case it's better to consider the default value. + * Hence not erroring out if Key is not found. + */ + auto_delete = dict_get_str_boolean (priv->opts, + GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE, + _gf_false); + + if (volinfo->snap_max_hard_limit < opt_max_hard) + effective_max_limit = volinfo->snap_max_hard_limit; + else + effective_max_limit = opt_max_hard; + + limit = (opt_max_soft * effective_max_limit)/100; + + if (volinfo->snap_count >= limit && auto_delete != _gf_true) { + gf_log (this->name, GF_LOG_WARNING, "Soft-limit " + "(value = %"PRIu64") of volume %s is reached. " + "Snapshot creation is not possible once effective " + "hard-limit (value = %"PRIu64") is reached.", + limit, volinfo->volname, effective_max_limit); + + ret = dict_set_int8 (dict, "soft-limit-reach", + _gf_true); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to " + "set soft limit exceed flag in " + "response dictionary"); + } + goto out; + } + ret = 0; +out: + return ret; +} + +/* This function initializes the parameter sys_hard_limit, + * sys_soft_limit and auto_delete value to the value set + * in dictionary, If value is not present then it is + * initialized to default values. Hence this function does not + * return any values. + */ +void +gd_get_snap_conf_values_if_present (dict_t *dict, uint64_t *sys_hard_limit, + uint64_t *sys_soft_limit) +{ + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + + GF_ASSERT (dict); + + /* "snap-max-hard-limit" might not be set by user explicitly, + * in that case it's better to consider the default value. + * Hence not erroring out if Key is not found. + */ + if (dict_get_uint64 (dict, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, + sys_hard_limit)) { + gf_log (this->name, GF_LOG_DEBUG, "%s is not present in" + "dictionary", + GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT); + } + + /* "snap-max-soft-limit" might not be set by user explicitly, + * in that case it's better to consider the default value. + * Hence not erroring out if Key is not found. + */ + if (dict_get_uint64 (dict, GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT, + sys_soft_limit)) { + gf_log (this->name, GF_LOG_DEBUG, "%s is not present in" + "dictionary", + GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT); + } +} diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.h b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.h new file mode 100644 index 00000000000..a5d82af559d --- /dev/null +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.h @@ -0,0 +1,200 @@ +/* + Copyright (c) 2015 Red Hat, Inc. + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ +#ifndef _GLUSTERD_SNAP_UTILS_H +#define _GLUSTERD_SNAP_UTILS_H + +int32_t +glusterd_snap_volinfo_find (char *volname, glusterd_snap_t *snap, + glusterd_volinfo_t **volinfo); + +int32_t +glusterd_snap_volinfo_find_from_parent_volname (char *origin_volname, + glusterd_snap_t *snap, + glusterd_volinfo_t **volinfo); + +int +glusterd_snap_volinfo_find_by_volume_id (uuid_t volume_id, + glusterd_volinfo_t **volinfo); + +int32_t +glusterd_add_snapd_to_dict (glusterd_volinfo_t *volinfo, + dict_t *dict, int32_t count); + +int +glusterd_compare_snap_time(struct list_head *, struct list_head *); + +int +glusterd_compare_snap_vol_time(struct list_head *, struct list_head *); + +int32_t +glusterd_snap_volinfo_restore (dict_t *dict, dict_t *rsp_dict, + glusterd_volinfo_t *new_volinfo, + glusterd_volinfo_t *snap_volinfo, + int32_t volcount); + +int32_t +glusterd_missed_snapinfo_new (glusterd_missed_snap_info **missed_snapinfo); + +int32_t +glusterd_missed_snap_op_new (glusterd_snap_op_t **snap_op); + +int32_t +glusterd_add_missed_snaps_to_dict (dict_t *rsp_dict, + glusterd_volinfo_t *snap_vol, + glusterd_brickinfo_t *brickinfo, + int32_t brick_number, int32_t op); + +int32_t +glusterd_add_missed_snaps_to_export_dict (dict_t *peer_data); + +int32_t +glusterd_import_friend_missed_snap_list (dict_t *peer_data); + +int +gd_restore_snap_volume (dict_t *dict, dict_t *rsp_dict, + glusterd_volinfo_t *orig_vol, + glusterd_volinfo_t *snap_vol, + int32_t volcount); + +int32_t +glusterd_mount_lvm_snapshot (glusterd_brickinfo_t *brickinfo, + char *brick_mount_path); + +int32_t +glusterd_umount (const char *path); + +int32_t +glusterd_add_snapshots_to_export_dict (dict_t *peer_data); + +int32_t +glusterd_compare_friend_snapshots (dict_t *peer_data, + glusterd_peerinfo_t *peerinfo); + +int32_t +glusterd_store_create_snap_dir (glusterd_snap_t *snap); + +int32_t +glusterd_copy_file (const char *source, const char *destination); + +int32_t +glusterd_copy_folder (const char *source, const char *destination); + +int32_t +glusterd_get_geo_rep_session (char *slave_key, char *origin_volname, + dict_t *gsync_slaves_dict, char *session, + char *slave); + +int32_t +glusterd_restore_geo_rep_files (glusterd_volinfo_t *snap_vol); + +int32_t +glusterd_copy_quota_files (glusterd_volinfo_t *src_vol, + glusterd_volinfo_t *dest_vol); + +int +glusterd_snap_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict); + +int +gd_add_vol_snap_details_to_dict (dict_t *dict, char *prefix, + glusterd_volinfo_t *volinfo); + +int +gd_add_brick_snap_details_to_dict (dict_t *dict, char *prefix, + glusterd_brickinfo_t *brickinfo); + +int +gd_import_new_brick_snap_details (dict_t *dict, char *prefix, + glusterd_brickinfo_t *brickinfo); + +int +gd_import_volume_snap_details (dict_t *dict, glusterd_volinfo_t *volinfo, + char *prefix, char *volname); + +int32_t +glusterd_snap_quorum_check (dict_t *dict, gf_boolean_t snap_volume, + char **op_errstr, + struct list_head *peers_list); + +int32_t +glusterd_snap_quorum_check_for_create (dict_t *dict, gf_boolean_t snap_volume, + char **op_errstr, + struct list_head *peers_list); + +int32_t +glusterd_snap_brick_create (glusterd_volinfo_t *snap_volinfo, + glusterd_brickinfo_t *brickinfo, + int32_t brick_count); + +int +glusterd_snapshot_restore_cleanup (dict_t *rsp_dict, + glusterd_volinfo_t *volinfo, + glusterd_snap_t *snap); + +int +glusterd_handle_snapd_option (glusterd_volinfo_t *volinfo); + +int32_t +glusterd_snapd_disconnect (glusterd_volinfo_t *volinfo); + +void +glusterd_get_snapd_dir (glusterd_volinfo_t *volinfo, + char *path, int path_len); + +void +glusterd_get_snapd_rundir (glusterd_volinfo_t *volinfo, + char *path, int path_len); + +void +glusterd_get_snapd_volfile (glusterd_volinfo_t *volinfo, + char *path, int path_len); + +void +glusterd_get_snapd_pidfile (glusterd_volinfo_t *volinfo, + char *path, int path_len); + +void +glusterd_set_snapd_socket_filepath (glusterd_volinfo_t *volinfo, + char *path, int path_len); + +gf_boolean_t +glusterd_is_snapd_running (glusterd_volinfo_t *volinfo); + +int +glusterd_snapd_stop (glusterd_volinfo_t *volinfo); + +int +glusterd_snapd_start (glusterd_volinfo_t *volinfo, gf_boolean_t wait); + +int +glusterd_is_snapd_enabled (glusterd_volinfo_t *volinfo); + +gf_boolean_t +glusterd_is_snapd_online (glusterd_volinfo_t *volinfo); + +void +glusterd_snapd_set_online_status (glusterd_volinfo_t *volinfo, + gf_boolean_t status); + +int +glusterd_restart_snapds (glusterd_conf_t *priv); + +int32_t +glusterd_check_and_set_config_limit (glusterd_conf_t *priv); + +int32_t +glusterd_is_snap_soft_limit_reached (glusterd_volinfo_t *volinfo, + dict_t *dict); + +void +gd_get_snap_conf_values_if_present (dict_t *opts, uint64_t *sys_hard_limit, + uint64_t *sys_soft_limit); + +#endif + diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot.c b/xlators/mgmt/glusterd/src/glusterd-snapshot.c index f77beaf76d2..759f5c460f6 100644 --- a/xlators/mgmt/glusterd/src/glusterd-snapshot.c +++ b/xlators/mgmt/glusterd/src/glusterd-snapshot.c @@ -54,6 +54,7 @@ #include "glusterd-volgen.h" #include "glusterd-mgmt.h" #include "glusterd-syncop.h" +#include "glusterd-snapshot-utils.h" #include "glusterfs3.h" diff --git a/xlators/mgmt/glusterd/src/glusterd-store.c b/xlators/mgmt/glusterd/src/glusterd-store.c index 1f31d196af2..bde97ceadc9 100644 --- a/xlators/mgmt/glusterd/src/glusterd-store.c +++ b/xlators/mgmt/glusterd/src/glusterd-store.c @@ -37,6 +37,7 @@ #include "glusterd-hooks.h" #include "store.h" #include "glusterd-store.h" +#include "glusterd-snapshot-utils.h" #include "rpc-clnt.h" #include "common-utils.h" diff --git a/xlators/mgmt/glusterd/src/glusterd-syncop.c b/xlators/mgmt/glusterd/src/glusterd-syncop.c index a910406f158..42a8cdcb685 100644 --- a/xlators/mgmt/glusterd/src/glusterd-syncop.c +++ b/xlators/mgmt/glusterd/src/glusterd-syncop.c @@ -19,6 +19,7 @@ #include "glusterd-op-sm.h" #include "glusterd-utils.h" #include "glusterd-locks.h" +#include "glusterd-snapshot-utils.h" extern glusterd_op_info_t opinfo; diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 06ac43aaf4b..a7c7bd9cb88 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -52,6 +52,7 @@ #include "glusterd-locks.h" #include "glusterd-messages.h" #include "glusterd-volgen.h" +#include "glusterd-snapshot-utils.h" #include "xdr-generic.h" #include @@ -648,223 +649,6 @@ gd_vol_is_geo_rep_active (glusterd_volinfo_t *volinfo) return active; } -/* - * glusterd_snap_geo_rep_restore: - * This function restores the atime and mtime of marker.tstamp - * if present from snapped marker.tstamp file. - */ -static int -glusterd_snap_geo_rep_restore (glusterd_volinfo_t *snap_volinfo, - glusterd_volinfo_t *new_volinfo) -{ - char vol_tstamp_file[PATH_MAX] = {0,}; - char snap_tstamp_file[PATH_MAX] = {0,}; - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; - int geo_rep_indexing_on = 0; - int ret = 0; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (snap_volinfo); - GF_ASSERT (new_volinfo); - - priv = this->private; - GF_ASSERT (priv); - - /* Check if geo-rep indexing is enabled, if yes, we need restore - * back the mtime of 'marker.tstamp' file. - */ - geo_rep_indexing_on = glusterd_volinfo_get_boolean (new_volinfo, - VKEY_MARKER_XTIME); - if (geo_rep_indexing_on == -1) { - gf_log (this->name, GF_LOG_DEBUG, "Failed" - " to check whether geo-rep-indexing enabled or not"); - ret = 0; - goto out; - } - - if (geo_rep_indexing_on == 1) { - GLUSTERD_GET_VOLUME_DIR (vol_tstamp_file, new_volinfo, priv); - strncat (vol_tstamp_file, "/marker.tstamp", - PATH_MAX - strlen(vol_tstamp_file) - 1); - GLUSTERD_GET_VOLUME_DIR (snap_tstamp_file, snap_volinfo, priv); - strncat (snap_tstamp_file, "/marker.tstamp", - PATH_MAX - strlen(snap_tstamp_file) - 1); - ret = gf_set_timestamp (snap_tstamp_file, vol_tstamp_file); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set atime and mtime of %s as of %s", - vol_tstamp_file, snap_tstamp_file); - goto out; - } - } - -out: - return ret; -} - -/* This function will copy snap volinfo to the new - * passed volinfo and regenerate backend store files - * for the restored snap. - * - * @param new_volinfo new volinfo - * @param snap_volinfo volinfo of snap volume - * - * @return 0 on success and -1 on failure - * - * TODO: Duplicate all members of volinfo, e.g. geo-rep sync slaves - */ -int32_t -glusterd_snap_volinfo_restore (dict_t *dict, dict_t *rsp_dict, - glusterd_volinfo_t *new_volinfo, - glusterd_volinfo_t *snap_volinfo, - int32_t volcount) -{ - char *value = NULL; - char key[PATH_MAX] = ""; - int32_t brick_count = -1; - int32_t ret = -1; - xlator_t *this = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - glusterd_brickinfo_t *new_brickinfo = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (dict); - GF_ASSERT (rsp_dict); - - GF_VALIDATE_OR_GOTO (this->name, new_volinfo, out); - GF_VALIDATE_OR_GOTO (this->name, snap_volinfo, out); - - brick_count = 0; - list_for_each_entry (brickinfo, &snap_volinfo->bricks, brick_list) { - brick_count++; - ret = glusterd_brickinfo_new (&new_brickinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to create " - "new brickinfo"); - goto out; - } - - /* Duplicate brickinfo */ - ret = glusterd_brickinfo_dup (brickinfo, new_brickinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to dup " - "brickinfo"); - goto out; - } - - /* Fetch values if present in dict These values won't - * be present in case of a missed restore. In that case - * it's fine to use the local node's value - */ - snprintf (key, sizeof (key), "snap%d.brick%d.path", - volcount, brick_count); - ret = dict_get_str (dict, key, &value); - if (!ret) - strncpy (new_brickinfo->path, value, - sizeof(new_brickinfo->path)); - - snprintf (key, sizeof (key), "snap%d.brick%d.snap_status", - volcount, brick_count); - ret = dict_get_int32 (dict, key, &new_brickinfo->snap_status); - - snprintf (key, sizeof (key), "snap%d.brick%d.device_path", - volcount, brick_count); - ret = dict_get_str (dict, key, &value); - if (!ret) - strncpy (new_brickinfo->device_path, value, - sizeof(new_brickinfo->device_path)); - - snprintf (key, sizeof (key), "snap%d.brick%d.fs_type", - volcount, brick_count); - ret = dict_get_str (dict, key, &value); - if (!ret) - strncpy (new_brickinfo->fstype, value, - sizeof(new_brickinfo->fstype)); - - snprintf (key, sizeof (key), "snap%d.brick%d.mnt_opts", - volcount, brick_count); - ret = dict_get_str (dict, key, &value); - if (!ret) - strncpy (new_brickinfo->mnt_opts, value, - sizeof(new_brickinfo->mnt_opts)); - - /* If the brick is not of this peer, or snapshot is missed * - * for the brick do not replace the xattr for it */ - if ((!uuid_compare (brickinfo->uuid, MY_UUID)) && - (brickinfo->snap_status != -1)) { - /* We need to replace the volume id of all the bricks - * to the volume id of the origin volume. new_volinfo - * has the origin volume's volume id*/ - ret = sys_lsetxattr (new_brickinfo->path, - GF_XATTR_VOL_ID_KEY, - new_volinfo->volume_id, - sizeof (new_volinfo->volume_id), - XATTR_REPLACE); - if (ret == -1) { - gf_log (this->name, GF_LOG_ERROR, "Failed to " - "set extended attribute %s on %s. " - "Reason: %s, snap: %s", - GF_XATTR_VOL_ID_KEY, - new_brickinfo->path, strerror (errno), - new_volinfo->volname); - goto out; - } - } - - /* If a snapshot is pending for this brick then - * restore should also be pending - */ - if (brickinfo->snap_status == -1) { - /* Adding missed delete to the dict */ - ret = glusterd_add_missed_snaps_to_dict - (rsp_dict, - snap_volinfo, - brickinfo, - brick_count, - GF_SNAP_OPTION_TYPE_RESTORE); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to add missed snapshot info " - "for %s:%s in the rsp_dict", - brickinfo->hostname, - brickinfo->path); - goto out; - } - } - - list_add_tail (&new_brickinfo->brick_list, - &new_volinfo->bricks); - /* ownership of new_brickinfo is passed to new_volinfo */ - new_brickinfo = NULL; - } - - /* Regenerate all volfiles */ - ret = glusterd_create_volfiles_and_notify_services (new_volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to regenerate volfiles"); - goto out; - } - - /* Restore geo-rep marker.tstamp's timestamp */ - ret = glusterd_snap_geo_rep_restore (snap_volinfo, new_volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Geo-rep: marker.tstamp's timestamp restoration failed"); - goto out; - } - -out: - if (ret && (NULL != new_brickinfo)) { - (void) glusterd_brickinfo_delete (new_brickinfo); - } - - return ret; -} - void glusterd_auth_cleanup (glusterd_volinfo_t *volinfo) { @@ -1530,42 +1314,6 @@ glusterd_volinfo_find_by_volume_id (uuid_t volume_id, glusterd_volinfo_t **volin return ret; } -int -glusterd_snap_volinfo_find_by_volume_id (uuid_t volume_id, - glusterd_volinfo_t **volinfo) -{ - int32_t ret = -1; - xlator_t *this = NULL; - glusterd_volinfo_t *voliter = NULL; - glusterd_snap_t *snap = NULL; - glusterd_conf_t *priv = NULL; - - this = THIS; - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (volinfo); - - if (uuid_is_null(volume_id)) { - gf_log (this->name, GF_LOG_WARNING, "Volume UUID is NULL"); - goto out; - } - - list_for_each_entry (snap, &priv->snapshots, snap_list) { - list_for_each_entry (voliter, &snap->volumes, vol_list) { - if (uuid_compare (volume_id, voliter->volume_id)) - continue; - *volinfo = voliter; - ret = 0; - goto out; - } - } - - gf_log (this->name, GF_LOG_WARNING, "Snap volume not found"); -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - int32_t glusterd_volinfo_find (char *volname, glusterd_volinfo_t **volinfo) { @@ -1595,68 +1343,6 @@ glusterd_volinfo_find (char *volname, glusterd_volinfo_t **volinfo) return ret; } -int32_t -glusterd_snap_volinfo_find (char *snap_volname, glusterd_snap_t *snap, - glusterd_volinfo_t **volinfo) -{ - int32_t ret = -1; - xlator_t *this = NULL; - glusterd_volinfo_t *snap_vol = NULL; - glusterd_conf_t *priv = NULL; - - this = THIS; - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (snap); - GF_ASSERT (snap_volname); - - list_for_each_entry (snap_vol, &snap->volumes, vol_list) { - if (!strcmp (snap_vol->volname, snap_volname)) { - ret = 0; - *volinfo = snap_vol; - goto out; - } - } - - gf_log (this->name, GF_LOG_WARNING, "Snap volume %s not found", - snap_volname); -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -int32_t -glusterd_snap_volinfo_find_from_parent_volname (char *origin_volname, - glusterd_snap_t *snap, - glusterd_volinfo_t **volinfo) -{ - int32_t ret = -1; - xlator_t *this = NULL; - glusterd_volinfo_t *snap_vol = NULL; - glusterd_conf_t *priv = NULL; - - this = THIS; - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (snap); - GF_ASSERT (origin_volname); - - list_for_each_entry (snap_vol, &snap->volumes, vol_list) { - if (!strcmp (snap_vol->parent_volname, origin_volname)) { - ret = 0; - *volinfo = snap_vol; - goto out; - } - } - - gf_log (this->name, GF_LOG_DEBUG, "Snap volume not found(snap: %s, " - "origin-volume: %s", snap->snapname, origin_volname); - -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - int32_t glusterd_service_stop (const char *service, char *pidfile, int sig, gf_boolean_t force_kill) @@ -2368,154 +2054,6 @@ out: return ret; } -/* Exports a bricks snapshot details only if required - * - * The details will be exported only if the cluster op-version is greather than - * 4, ie. snapshot is supported in the cluster - */ -int -gd_add_brick_snap_details_to_dict (dict_t *dict, char *prefix, - glusterd_brickinfo_t *brickinfo) -{ - int ret = -1; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; - char key[256] = {0,}; - - this = THIS; - GF_ASSERT (this != NULL); - conf = this->private; - GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); - - GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (brickinfo != NULL), out); - - if (conf->op_version < GD_OP_VERSION_3_6_0) { - ret = 0; - goto out; - } - - snprintf (key, sizeof (key), "%s.snap_status", prefix); - ret = dict_set_int32 (dict, key, brickinfo->snap_status); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to set snap_status for %s:%s", - brickinfo->hostname, brickinfo->path); - goto out; - } - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.device_path", prefix); - ret = dict_set_str (dict, key, brickinfo->device_path); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to set snap_device for %s:%s", - brickinfo->hostname, brickinfo->path); - goto out; - } - - snprintf (key, sizeof (key), "%s.fs_type", prefix); - ret = dict_set_str (dict, key, brickinfo->fstype); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to set fstype for %s:%s", - brickinfo->hostname, brickinfo->path); - goto out; - } - - snprintf (key, sizeof (key), "%s.mnt_opts", prefix); - ret = dict_set_str (dict, key, brickinfo->mnt_opts); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to set mnt_opts for %s:%s", - brickinfo->hostname, brickinfo->path); - goto out; - } - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.mount_dir", prefix); - ret = dict_set_str (dict, key, brickinfo->mount_dir); - if (ret) - gf_log (this->name, GF_LOG_ERROR, - "Failed to set mount_dir for %s:%s", - brickinfo->hostname, brickinfo->path); - -out: - return ret; -} - -/* Exports a volumes snapshot details only if required. - * - * The snapshot details will only be exported if the cluster op-version is - * greater than 4, ie. snapshot is supported in the cluster - */ -int -gd_add_vol_snap_details_to_dict (dict_t *dict, char *prefix, - glusterd_volinfo_t *volinfo) -{ - int ret = -1; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; - char key[256] = {0,}; - - this = THIS; - GF_ASSERT (this != NULL); - conf = this->private; - GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); - - GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (volinfo != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); - - if (conf->op_version < GD_OP_VERSION_3_6_0) { - ret =0; - goto out; - } - - snprintf (key, sizeof (key), "%s.restored_from_snap", prefix); - ret = dict_set_dynstr_with_alloc - (dict, key, - uuid_utoa (volinfo->restored_from_snap)); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to set %s for volume" - "%s", key, volinfo->volname); - goto out; - } - - if (strlen (volinfo->parent_volname) > 0) { - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.parent_volname", prefix); - ret = dict_set_dynstr_with_alloc (dict, key, - volinfo->parent_volname); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to set %s " - "for volume %s", key, volinfo->volname); - goto out; - } - } - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.is_snap_volume", prefix); - ret = dict_set_uint32 (dict, key, volinfo->is_snap_volume); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to set %s for volume" - "%s", key, volinfo->volname); - goto out; - } - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.snap-max-hard-limit", prefix); - ret = dict_set_uint64 (dict, key, volinfo->snap_max_hard_limit); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to set %s for volume" - "%s", key, volinfo->volname); - } - -out: - return ret; -} - /* The prefix represents the type of volume to be added. * It will be "volume" for normal volumes, and snap# like * snap1, snap2, for snapshot volumes @@ -2933,259 +2471,24 @@ out: } int32_t -glusterd_add_missed_snaps_to_export_dict (dict_t *peer_data) +glusterd_add_volumes_to_export_dict (dict_t **peer_data) { - char name_buf[PATH_MAX] = ""; - char value[PATH_MAX] = ""; - int32_t missed_snap_count = 0; - int32_t ret = -1; - glusterd_conf_t *priv = NULL; - glusterd_missed_snap_info *missed_snapinfo = NULL; - glusterd_snap_op_t *snap_opinfo = NULL; - xlator_t *this = NULL; + int32_t ret = -1; + dict_t *dict = NULL; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; + int32_t count = 0; + glusterd_dict_ctx_t ctx = {0}; + xlator_t *this = NULL; this = THIS; GF_ASSERT (this); - GF_ASSERT (peer_data); - priv = this->private; GF_ASSERT (priv); - /* Add the missed_entries in the dict */ - list_for_each_entry (missed_snapinfo, &priv->missed_snaps_list, - missed_snaps) { - list_for_each_entry (snap_opinfo, - &missed_snapinfo->snap_ops, - snap_ops_list) { - snprintf (name_buf, sizeof(name_buf), - "missed_snaps_%d", missed_snap_count); - snprintf (value, sizeof(value), "%s:%s=%s:%d:%s:%d:%d", - missed_snapinfo->node_uuid, - missed_snapinfo->snap_uuid, - snap_opinfo->snap_vol_id, - snap_opinfo->brick_num, - snap_opinfo->brick_path, - snap_opinfo->op, - snap_opinfo->status); - - ret = dict_set_dynstr_with_alloc (peer_data, name_buf, - value); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set %s", - name_buf); - goto out; - } - missed_snap_count++; - } - } - - ret = dict_set_int32 (peer_data, "missed_snap_count", - missed_snap_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set missed_snap_count"); - goto out; - } - -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -int32_t -glusterd_add_snap_to_dict (glusterd_snap_t *snap, dict_t *peer_data, - int32_t snap_count) -{ - char buf[NAME_MAX] = ""; - char prefix[NAME_MAX] = ""; - int32_t ret = -1; - int32_t volcount = 0; - glusterd_volinfo_t *volinfo = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - gf_boolean_t host_bricks = _gf_false; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (snap); - GF_ASSERT (peer_data); - - snprintf (prefix, sizeof(prefix), "snap%d", snap_count); - - list_for_each_entry (volinfo, &snap->volumes, vol_list) { - volcount++; - ret = glusterd_add_volume_to_dict (volinfo, peer_data, - volcount, prefix); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to add snap:%s volume:%s " - "to peer_data dict for handshake", - snap->snapname, volinfo->volname); - goto out; - } - - if (glusterd_is_volume_quota_enabled (volinfo)) { - - ret = glusterd_vol_add_quota_conf_to_dict (volinfo, - peer_data, - volcount, - prefix); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to add quota conf for " - "snap:%s volume:%s to peer_data " - "dict for handshake", snap->snapname, - volinfo->volname); - goto out; - } - } - - list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - if (!uuid_compare (brickinfo->uuid, MY_UUID)) { - host_bricks = _gf_true; - break; - } - } - } - - snprintf (buf, sizeof(buf), "%s.host_bricks", prefix); - ret = dict_set_int8 (peer_data, buf, (int8_t) host_bricks); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set host_bricks for snap %s", - snap->snapname); - goto out; - } - - snprintf (buf, sizeof(buf), "%s.volcount", prefix); - ret = dict_set_int32 (peer_data, buf, volcount); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set volcount for snap %s", - snap->snapname); - goto out; - } - - snprintf (buf, sizeof(buf), "%s.snapname", prefix); - ret = dict_set_dynstr_with_alloc (peer_data, buf, snap->snapname); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set snapname for snap %s", - snap->snapname); - goto out; - } - - snprintf (buf, sizeof(buf), "%s.snap_id", prefix); - ret = dict_set_dynstr_with_alloc (peer_data, buf, - uuid_utoa (snap->snap_id)); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set snap_id for snap %s", - snap->snapname); - goto out; - } - - if (snap->description) { - snprintf (buf, sizeof(buf), "%s.snapid", prefix); - ret = dict_set_dynstr_with_alloc (peer_data, buf, - snap->description); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set description for snap %s", - snap->snapname); - goto out; - } - } - - snprintf (buf, sizeof(buf), "%s.time_stamp", prefix); - ret = dict_set_int64 (peer_data, buf, (int64_t)snap->time_stamp); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set time_stamp for snap %s", - snap->snapname); - goto out; - } - - snprintf (buf, sizeof(buf), "%s.snap_restored", prefix); - ret = dict_set_int8 (peer_data, buf, snap->snap_restored); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set snap_restored for snap %s", - snap->snapname); - goto out; - } - - snprintf (buf, sizeof(buf), "%s.snap_status", prefix); - ret = dict_set_int32 (peer_data, buf, snap->snap_status); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set snap_status for snap %s", - snap->snapname); - goto out; - } -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -int32_t -glusterd_add_snapshots_to_export_dict (dict_t *peer_data) -{ - int32_t snap_count = 0; - int32_t ret = -1; - glusterd_conf_t *priv = NULL; - glusterd_snap_t *snap = NULL; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (peer_data); - - list_for_each_entry (snap, &priv->snapshots, snap_list) { - snap_count++; - ret = glusterd_add_snap_to_dict (snap, peer_data, snap_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to add snap(%s) to the " - " peer_data dict for handshake", - snap->snapname); - goto out; - } - } - - ret = dict_set_int32 (peer_data, "snap_count", snap_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set snap_count"); - goto out; - } - -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -int32_t -glusterd_add_volumes_to_export_dict (dict_t **peer_data) -{ - int32_t ret = -1; - dict_t *dict = NULL; - glusterd_conf_t *priv = NULL; - glusterd_volinfo_t *volinfo = NULL; - int32_t count = 0; - glusterd_dict_ctx_t ctx = {0}; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - - dict = dict_new (); - if (!dict) - goto out; + dict = dict_new (); + if (!dict) + goto out; list_for_each_entry (volinfo, &priv->volumes, vol_list) { count++; @@ -3781,82 +3084,6 @@ out: return ret; } -/* Imports the snapshot details of a brick if required and available - * - * Snapshot details will be imported only if the cluster op-verison is >= 4 - */ -int -gd_import_new_brick_snap_details (dict_t *dict, char *prefix, - glusterd_brickinfo_t *brickinfo) -{ - int ret = -1; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; - char key[512] = {0,}; - char *snap_device = NULL; - char *fs_type = NULL; - char *mnt_opts = NULL; - char *mount_dir = NULL; - - this = THIS; - GF_ASSERT (this != NULL); - conf = this->private; - GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); - - GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (brickinfo != NULL), out); - - if (conf->op_version < GD_OP_VERSION_3_6_0) { - ret = 0; - goto out; - } - - snprintf (key, sizeof (key), "%s.snap_status", prefix); - ret = dict_get_int32 (dict, key, &brickinfo->snap_status); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); - goto out; - } - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.device_path", prefix); - ret = dict_get_str (dict, key, &snap_device); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); - goto out; - } - strcpy (brickinfo->device_path, snap_device); - - snprintf (key, sizeof (key), "%s.fs_type", prefix); - ret = dict_get_str (dict, key, &fs_type); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); - goto out; - } - strcpy (brickinfo->fstype, fs_type); - - snprintf (key, sizeof (key), "%s.mnt_opts", prefix); - ret = dict_get_str (dict, key, &mnt_opts); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); - goto out; - } - strcpy (brickinfo->mnt_opts, mnt_opts); - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.mount_dir", prefix); - ret = dict_get_str (dict, key, &mount_dir); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload", key); - goto out; - } - strcpy (brickinfo->mount_dir, mount_dir); - -out: - return ret; -} - /* The prefix represents the type of volume to be added. * It will be "volume" for normal volumes, and snap# like * snap1, snap2, for snapshot volumes @@ -3987,7 +3214,7 @@ out: * It will be "volume" for normal volumes, and snap# like * snap1, snap2, for snapshot volumes */ -static int +int glusterd_import_quota_conf (dict_t *peer_data, int vol_idx, glusterd_volinfo_t *new_volinfo, char *prefix) @@ -4137,67 +3364,6 @@ out: return ret; } -/* - * Imports the snapshot details of a volume if required and available - * - * Snapshot details will be imported only if cluster.op_version is greater than - * or equal to GD_OP_VERSION_3_6_0, the op-version from which volume snapshot is - * supported. - */ -int -gd_import_volume_snap_details (dict_t *dict, glusterd_volinfo_t *volinfo, - char *prefix, char *volname) -{ - int ret = -1; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; - char key[256] = {0,}; - char *restored_snap = NULL; - - this = THIS; - GF_ASSERT (this != NULL); - conf = this->private; - GF_VALIDATE_OR_GOTO (this->name, (conf != NULL), out); - - GF_VALIDATE_OR_GOTO (this->name, (dict != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (volinfo != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (prefix != NULL), out); - GF_VALIDATE_OR_GOTO (this->name, (volname != NULL), out); - - if (conf->op_version < GD_OP_VERSION_3_6_0) { - ret = 0; - goto out; - } - - snprintf (key, sizeof (key), "%s.is_snap_volume", prefix); - ret = dict_get_uint32 (dict, key, &volinfo->is_snap_volume); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload " - "for %s", key, volname); - goto out; - } - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.restored_from_snap", prefix); - ret = dict_get_str (dict, key, &restored_snap); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload " - "for %s", key, volname); - goto out; - } - - uuid_parse (restored_snap, volinfo->restored_from_snap); - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.snap-max-hard-limit", prefix); - ret = dict_get_uint64 (dict, key, - &volinfo->snap_max_hard_limit); - if (ret) - gf_log (this->name, GF_LOG_ERROR, "%s missing in payload " - "for %s", key, volname); -out: - return ret; -} /* The prefix represents the type of volume to be added. * It will be "volume" for normal volumes, and snap# like * snap1, snap2, for snapshot volumes @@ -4934,2867 +4100,1975 @@ out: } int32_t -glusterd_perform_missed_op (glusterd_snap_t *snap, int32_t op) +glusterd_compare_friend_data (dict_t *peer_data, int32_t *status, + char *hostname) { - dict_t *dict = NULL; - int32_t ret = -1; - glusterd_conf_t *priv = NULL; - glusterd_volinfo_t *snap_volinfo = NULL; - glusterd_volinfo_t *volinfo = NULL; - glusterd_volinfo_t *tmp = NULL; - xlator_t *this = NULL; - uuid_t null_uuid = {0}; + int32_t ret = -1; + int32_t count = 0; + int i = 1; + gf_boolean_t update = _gf_false; + gf_boolean_t stale_nfs = _gf_false; + gf_boolean_t stale_shd = _gf_false; + gf_boolean_t stale_qd = _gf_false; + xlator_t *this = NULL; this = THIS; GF_ASSERT (this); + GF_ASSERT (peer_data); + GF_ASSERT (status); - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (snap); - - dict = dict_new(); - if (!dict) { - gf_log (this->name, GF_LOG_ERROR, "Unable to create dict"); - ret = -1; + ret = glusterd_import_global_opts (peer_data); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Importing global " + "options failed"); goto out; } - switch (op) { - case GF_SNAP_OPTION_TYPE_DELETE: - ret = glusterd_snap_remove (dict, snap, _gf_true, _gf_false); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to remove snap"); - goto out; - } - - break; - case GF_SNAP_OPTION_TYPE_RESTORE: - list_for_each_entry_safe (snap_volinfo, tmp, - &snap->volumes, vol_list) { - ret = glusterd_volinfo_find - (snap_volinfo->parent_volname, - &volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Could not get volinfo of %s", - snap_volinfo->parent_volname); - goto out; - } - - volinfo->version--; - uuid_copy (volinfo->restored_from_snap, null_uuid); + ret = dict_get_int32 (peer_data, "count", &count); + if (ret) + goto out; - /* gd_restore_snap_volume() uses the dict and volcount - * to fetch snap brick info from other nodes, which were - * collected during prevalidation. As this is an ad-hoc - * op and only local node's data matter, hence sending - * volcount as 0 and re-using the same dict because we - * need not record any missed creates in the rsp_dict. - */ - ret = gd_restore_snap_volume (dict, dict, volinfo, - snap_volinfo, 0); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to restore snap for %s", - snap->snapname); - volinfo->version++; - goto out; - } + while (i <= count) { + ret = glusterd_compare_friend_volume (peer_data, i, status, + hostname); + if (ret) + goto out; - ret = glusterd_snapshot_restore_cleanup (dict, volinfo, - snap); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to perform snapshot restore " - "cleanup for %s volume", - snap_volinfo->parent_volname); - goto out; - } + if (GLUSTERD_VOL_COMP_RJT == *status) { + ret = 0; + goto out; } + if (GLUSTERD_VOL_COMP_UPDATE_REQ == *status) + update = _gf_true; - break; - default: - /* The entry must be a create, delete, or - * restore entry - */ - gf_log (this->name, GF_LOG_ERROR, "Invalid missed snap entry"); - ret = -1; - goto out; + i++; } -out: - dict_unref (dict); - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -/* Perform missed deletes and restores on this node */ -int32_t -glusterd_perform_missed_snap_ops () -{ - int32_t ret = -1; - int32_t op_status = -1; - glusterd_conf_t *priv = NULL; - glusterd_missed_snap_info *missed_snapinfo = NULL; - glusterd_snap_op_t *snap_opinfo = NULL; - glusterd_snap_t *snap = NULL; - uuid_t snap_uuid = {0,}; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - - priv = this->private; - GF_ASSERT (priv); - - list_for_each_entry (missed_snapinfo, &priv->missed_snaps_list, - missed_snaps) { - /* If the pending snap_op is not for this node then continue */ - if (strcmp (missed_snapinfo->node_uuid, uuid_utoa (MY_UUID))) - continue; - - /* Find the snap id */ - uuid_parse (missed_snapinfo->snap_uuid, snap_uuid); - snap = NULL; - snap = glusterd_find_snap_by_id (snap_uuid); - if (!snap) { - /* If the snap is not found, then a delete or a - * restore can't be pending on that snap_uuid. - */ - gf_log (this->name, GF_LOG_DEBUG, - "Not a pending delete or restore op"); - continue; - } - - op_status = GD_MISSED_SNAP_PENDING; - list_for_each_entry (snap_opinfo, &missed_snapinfo->snap_ops, - snap_ops_list) { - /* If the snap_op is create or its status is - * GD_MISSED_SNAP_DONE then continue - */ - if ((snap_opinfo->status == GD_MISSED_SNAP_DONE) || - (snap_opinfo->op == GF_SNAP_OPTION_TYPE_CREATE)) - continue; - - /* Perform the actual op for the first time for - * this snap, and mark the snap_status as - * GD_MISSED_SNAP_DONE. For other entries for the same - * snap, just mark the entry as done. - */ - if (op_status == GD_MISSED_SNAP_PENDING) { - ret = glusterd_perform_missed_op - (snap, - snap_opinfo->op); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to perform missed snap op"); - goto out; - } - op_status = GD_MISSED_SNAP_DONE; - } - - snap_opinfo->status = GD_MISSED_SNAP_DONE; + if (update) { + if (glusterd_is_nodesvc_running ("nfs")) + stale_nfs = _gf_true; + if (glusterd_is_nodesvc_running ("glustershd")) + stale_shd = _gf_true; + if (glusterd_is_nodesvc_running ("quotad")) + stale_qd = _gf_true; + ret = glusterd_import_friend_volumes (peer_data); + if (ret) + goto out; + if (_gf_false == glusterd_are_all_volumes_stopped ()) { + ret = glusterd_nodesvcs_handle_graph_change (NULL); + } else { + if (stale_nfs) + glusterd_nfs_server_stop (); + if (stale_shd) + glusterd_shd_stop (); + if (stale_qd) + glusterd_quotad_stop (); } } - ret = 0; out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, + "Returning with ret: %d, status: %d", ret, *status); return ret; } -/* Import friend volumes missed_snap_list and update * - * missed_snap_list if need be */ -int32_t -glusterd_import_friend_missed_snap_list (dict_t *peer_data) +void +glusterd_get_nodesvc_dir (char *server, char *workdir, + char *path, size_t len) { - int32_t missed_snap_count = -1; - int32_t ret = -1; - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (peer_data); - - priv = this->private; - GF_ASSERT (priv); - - /* Add the friends missed_snaps entries to the in-memory list */ - ret = dict_get_int32 (peer_data, "missed_snap_count", - &missed_snap_count); - if (ret) { - gf_log (this->name, GF_LOG_INFO, - "No missed snaps"); - ret = 0; - goto out; - } + GF_ASSERT (len == PATH_MAX); + snprintf (path, len, "%s/%s", workdir, server); +} - ret = glusterd_add_missed_snaps_to_list (peer_data, - missed_snap_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to add missed snaps to list"); - goto out; - } +void +glusterd_get_nodesvc_rundir (char *server, char *workdir, + char *path, size_t len) +{ + char dir[PATH_MAX] = {0}; + GF_ASSERT (len == PATH_MAX); - ret = glusterd_perform_missed_snap_ops (); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to perform snap operations"); - /* Not going to out at this point coz some * - * missed ops might have been performed. We * - * need to persist the current list * - */ - } + glusterd_get_nodesvc_dir (server, workdir, dir, sizeof (dir)); + snprintf (path, len, "%s/run", dir); +} - ret = glusterd_store_update_missed_snaps (); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to update missed_snaps_list"); - goto out; - } +void +glusterd_get_nodesvc_pidfile (char *server, char *workdir, + char *path, size_t len) +{ + char dir[PATH_MAX] = {0}; + GF_ASSERT (len == PATH_MAX); -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; + glusterd_get_nodesvc_rundir (server, workdir, dir, sizeof (dir)); + snprintf (path, len, "%s/%s.pid", dir, server); } -/* Check for the peer_snap_name in the list of existing snapshots. - * If a snap exists with the same name and a different snap_id, then - * there is a conflict. Set conflict as _gf_true, and snap to the - * conflicting snap object. If a snap exists with the same name, and the - * same snap_id, then there is no conflict. Set conflict as _gf_false - * and snap to the existing snap object. If no snap exists with the - * peer_snap_name, then there is no conflict. Set conflict as _gf_false - * and snap to NULL. - */ void -glusterd_is_peer_snap_conflicting (char *peer_snap_name, char *peer_snap_id, - gf_boolean_t *conflict, - glusterd_snap_t **snap, char *hostname) +glusterd_get_nodesvc_volfile (char *server, char *workdir, + char *volfile, size_t len) { - uuid_t peer_snap_uuid = {0,}; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (peer_snap_name); - GF_ASSERT (peer_snap_id); - GF_ASSERT (conflict); - GF_ASSERT (snap); - GF_ASSERT (hostname); + char dir[PATH_MAX] = {0,}; + GF_ASSERT (len == PATH_MAX); - *snap = glusterd_find_snap_by_name (peer_snap_name); - if (*snap) { - uuid_parse (peer_snap_id, peer_snap_uuid); - if (!uuid_compare (peer_snap_uuid, (*snap)->snap_id)) { - /* Current node contains the same snap having - * the same snapname and snap_id - */ - gf_log (this->name, GF_LOG_DEBUG, - "Snapshot %s from peer %s present in " - "localhost", peer_snap_name, hostname); - *conflict = _gf_false; - } else { - /* Current node contains the same snap having - * the same snapname but different snap_id - */ - gf_log (this->name, GF_LOG_DEBUG, - "Snapshot %s from peer %s conflicts with " - "snapshot in localhost", peer_snap_name, - hostname); - *conflict = _gf_true; - } - } else { - /* Peer contains snapshots missing on the current node */ - gf_log (this->name, GF_LOG_INFO, - "Snapshot %s from peer %s missing on localhost", - peer_snap_name, hostname); - *conflict = _gf_false; - } + glusterd_get_nodesvc_dir (server, workdir, dir, sizeof (dir)); + if (strcmp ("quotad", server) != 0) + snprintf (volfile, len, "%s/%s-server.vol", dir, server); + else + snprintf (volfile, len, "%s/%s.vol", dir, server); } -/* Check if the local node is hosting any bricks for the given snapshot */ -gf_boolean_t -glusterd_are_snap_bricks_local (glusterd_snap_t *snap) +void +glusterd_nodesvc_set_online_status (char *server, gf_boolean_t status) { - gf_boolean_t is_local = _gf_false; - glusterd_volinfo_t *volinfo = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (snap); + glusterd_conf_t *priv = NULL; - list_for_each_entry (volinfo, &snap->volumes, vol_list) { - list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - if (!uuid_compare (brickinfo->uuid, MY_UUID)) { - is_local = _gf_true; - goto out; - } - } - } + GF_ASSERT (server); + priv = THIS->private; + GF_ASSERT (priv); + GF_ASSERT (priv->shd); + GF_ASSERT (priv->nfs); + GF_ASSERT (priv->quotad); -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", is_local); - return is_local; + if (!strcmp("glustershd", server)) + priv->shd->online = status; + else if (!strcmp ("nfs", server)) + priv->nfs->online = status; + else if (!strcmp ("quotad", server)) + priv->quotad->online = status; } -/* Check if the peer has missed any snap delete - * or restore for the given snap_id - */ gf_boolean_t -glusterd_peer_has_missed_snap_delete (glusterd_peerinfo_t *peerinfo, - char *peer_snap_id) +glusterd_is_nodesvc_online (char *server) { - char *peer_uuid = NULL; - gf_boolean_t missed_delete = _gf_false; - glusterd_conf_t *priv = NULL; - glusterd_missed_snap_info *missed_snapinfo = NULL; - glusterd_snap_op_t *snap_opinfo = NULL; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (peerinfo); - GF_ASSERT (peer_snap_id); + glusterd_conf_t *conf = NULL; + gf_boolean_t online = _gf_false; - peer_uuid = uuid_utoa (peerinfo->uuid); + GF_ASSERT (server); + conf = THIS->private; + GF_ASSERT (conf); + GF_ASSERT (conf->shd); + GF_ASSERT (conf->nfs); + GF_ASSERT (conf->quotad); - list_for_each_entry (missed_snapinfo, &priv->missed_snaps_list, - missed_snaps) { - /* Look for missed snap for the same peer, and - * the same snap_id - */ - if ((!strcmp (peer_uuid, missed_snapinfo->node_uuid)) && - (!strcmp (peer_snap_id, missed_snapinfo->snap_uuid))) { - /* Check if the missed snap's op is delete and the - * status is pending - */ - list_for_each_entry (snap_opinfo, - &missed_snapinfo->snap_ops, - snap_ops_list) { - if (((snap_opinfo->op == - GF_SNAP_OPTION_TYPE_DELETE) || - (snap_opinfo->op == - GF_SNAP_OPTION_TYPE_RESTORE)) && - (snap_opinfo->status == - GD_MISSED_SNAP_PENDING)) { - missed_delete = _gf_true; - goto out; - } - } - } - } + if (!strcmp (server, "glustershd")) + online = conf->shd->online; + else if (!strcmp (server, "nfs")) + online = conf->nfs->online; + else if (!strcmp (server, "quotad")) + online = conf->quotad->online; -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", missed_delete); - return missed_delete; + return online; } -/* Genrate and store snap volfiles for imported snap object */ int32_t -glusterd_gen_snap_volfiles (glusterd_volinfo_t *snap_vol, char *peer_snap_name) +glusterd_nodesvc_set_socket_filepath (char *rundir, uuid_t uuid, + char *socketpath, int len) { - int32_t ret = -1; - xlator_t *this = NULL; - glusterd_volinfo_t *parent_volinfo = NULL; - glusterd_brickinfo_t *brickinfo = NULL; + char sockfilepath[PATH_MAX] = {0,}; - this = THIS; - GF_ASSERT (this); - GF_ASSERT (snap_vol); - GF_ASSERT (peer_snap_name); + snprintf (sockfilepath, sizeof (sockfilepath), "%s/run-%s", + rundir, uuid_utoa (uuid)); - ret = glusterd_store_volinfo (snap_vol, GLUSTERD_VOLINFO_VER_AC_NONE); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to store snapshot " - "volinfo (%s) for snap %s", snap_vol->volname, - peer_snap_name); - goto out; - } + glusterd_set_socket_filepath (sockfilepath, socketpath, len); + return 0; +} - ret = generate_brick_volfiles (snap_vol); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "generating the brick volfiles for the " - "snap %s failed", peer_snap_name); - goto out; - } +struct rpc_clnt* +glusterd_pending_node_get_rpc (glusterd_pending_node_t *pending_node) +{ + struct rpc_clnt *rpc = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + nodesrv_t *shd = NULL; + glusterd_volinfo_t *volinfo = NULL; + nodesrv_t *nfs = NULL; + nodesrv_t *quotad = NULL; + glusterd_snapd_t *snapd = NULL; - ret = generate_client_volfiles (snap_vol, GF_CLIENT_TRUSTED); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "generating the trusted client volfiles for " - "the snap %s failed", peer_snap_name); - goto out; - } + GF_VALIDATE_OR_GOTO (THIS->name, pending_node, out); + GF_VALIDATE_OR_GOTO (THIS->name, pending_node->node, out); - ret = generate_client_volfiles (snap_vol, GF_CLIENT_OTHER); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "generating the client volfiles for the " - "snap %s failed", peer_snap_name); - goto out; - } + if (pending_node->type == GD_NODE_BRICK) { + brickinfo = pending_node->node; + rpc = brickinfo->rpc; - ret = glusterd_volinfo_find (snap_vol->parent_volname, - &parent_volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Parent volinfo " - "not found for %s volume of snap %s", - snap_vol->volname, peer_snap_name); - goto out; - } + } else if (pending_node->type == GD_NODE_SHD) { + shd = pending_node->node; + rpc = shd->rpc; - glusterd_list_add_snapvol (parent_volinfo, snap_vol); + } else if (pending_node->type == GD_NODE_REBALANCE) { + volinfo = pending_node->node; + if (volinfo->rebal.defrag) + rpc = volinfo->rebal.defrag->rpc; - snap_vol->status = GLUSTERD_STATUS_STARTED; + } else if (pending_node->type == GD_NODE_NFS) { + nfs = pending_node->node; + rpc = nfs->rpc; - ret = glusterd_store_volinfo (snap_vol, GLUSTERD_VOLINFO_VER_AC_NONE); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to store snap volinfo"); - goto out; + } else if (pending_node->type == GD_NODE_QUOTAD) { + quotad = pending_node->node; + rpc = quotad->rpc; + } else if (pending_node->type == GD_NODE_SNAPD) { + snapd = pending_node->node; + rpc = snapd->rpc; + } else { + GF_ASSERT (0); } + out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; + return rpc; } -/* Import snapshot info from peer_data and add it to priv */ -int32_t -glusterd_import_friend_snap (dict_t *peer_data, int32_t snap_count, - char *peer_snap_name, char *peer_snap_id) -{ - char buf[NAME_MAX] = ""; - char prefix[NAME_MAX] = ""; - dict_t *dict = NULL; - glusterd_snap_t *snap = NULL; - glusterd_volinfo_t *snap_vol = NULL; - glusterd_conf_t *priv = NULL; - int32_t ret = -1; - int32_t volcount = -1; - int32_t i = -1; - xlator_t *this = NULL; +struct rpc_clnt* +glusterd_nodesvc_get_rpc (char *server) +{ + glusterd_conf_t *priv = NULL; + struct rpc_clnt *rpc = NULL; - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (peer_data); - GF_ASSERT (peer_snap_name); - GF_ASSERT (peer_snap_id); - - snprintf (prefix, sizeof(prefix), "snap%d", snap_count); - - snap = glusterd_new_snap_object (); - if (!snap) { - gf_log (this->name, GF_LOG_ERROR, "Could not create " - "the snap object for snap %s", peer_snap_name); - goto out; - } - - dict = dict_new (); - if (!dict) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to create dict"); - ret = -1; - goto out; - } - - strcpy (snap->snapname, peer_snap_name); - uuid_parse (peer_snap_id, snap->snap_id); + GF_ASSERT (server); + priv = THIS->private; + GF_ASSERT (priv); + GF_ASSERT (priv->shd); + GF_ASSERT (priv->nfs); + GF_ASSERT (priv->quotad); - snprintf (buf, sizeof(buf), "%s.snapid", prefix); - ret = dict_get_str (peer_data, buf, &snap->description); + if (!strcmp (server, "glustershd")) + rpc = priv->shd->rpc; + else if (!strcmp (server, "nfs")) + rpc = priv->nfs->rpc; + else if (!strcmp (server, "quotad")) + rpc = priv->quotad->rpc; - snprintf (buf, sizeof(buf), "%s.time_stamp", prefix); - ret = dict_get_int64 (peer_data, buf, &snap->time_stamp); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to get time_stamp for snap %s", - peer_snap_name); - goto out; - } + return rpc; +} - snprintf (buf, sizeof(buf), "%s.snap_restored", prefix); - ret = dict_get_int8 (peer_data, buf, (int8_t *) &snap->snap_restored); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to get snap_restored for snap %s", - peer_snap_name); - goto out; - } +int32_t +glusterd_nodesvc_set_rpc (char *server, struct rpc_clnt *rpc) +{ + int ret = 0; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; - snprintf (buf, sizeof(buf), "%s.snap_status", prefix); - ret = dict_get_int32 (peer_data, buf, (int32_t *) &snap->snap_status); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to get snap_status for snap %s", - peer_snap_name); - goto out; - } + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + GF_ASSERT (priv->shd); + GF_ASSERT (priv->nfs); + GF_ASSERT (priv->quotad); - /* If the snap is scheduled to be decommissioned, then - * don't accept the snap */ - if (snap->snap_status == GD_SNAP_STATUS_DECOMMISSION) { - gf_log (this->name, GF_LOG_DEBUG, - "The snap(%s) is scheduled to be decommissioned " - "Not accepting the snap.", peer_snap_name); - glusterd_snap_remove (dict, snap, - _gf_true, _gf_true); - ret = 0; - goto out; - } + if (!strcmp ("glustershd", server)) + priv->shd->rpc = rpc; + else if (!strcmp ("nfs", server)) + priv->nfs->rpc = rpc; + else if (!strcmp ("quotad", server)) + priv->quotad->rpc = rpc; - snprintf (buf, sizeof(buf), "%s.volcount", prefix); - ret = dict_get_int32 (peer_data, buf, &volcount); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to get volcount for snap %s", - peer_snap_name); - goto out; - } + return ret; +} - ret = glusterd_store_create_snap_dir (snap); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Failed to create snap dir"); - goto out; - } +int32_t +glusterd_nodesvc_connect (char *server, char *socketpath) +{ + int ret = 0; + dict_t *options = NULL; + struct rpc_clnt *rpc = NULL; + glusterd_conf_t *priv = THIS->private; - list_add_order (&snap->snap_list, &priv->snapshots, - glusterd_compare_snap_time); + rpc = glusterd_nodesvc_get_rpc (server); - for (i = 1; i <= volcount; i++) { - ret = glusterd_import_volinfo (peer_data, i, - &snap_vol, prefix); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to import snap volinfo for " - "snap %s", peer_snap_name); + if (rpc == NULL) { + /* Setting frame-timeout to 10mins (600seconds). + * Unix domain sockets ensures that the connection is reliable. + * The default timeout of 30mins used for unreliable network + * connections is too long for unix domain socket connections. + */ + ret = rpc_transport_unix_options_build (&options, socketpath, + 600); + if (ret) goto out; - } - - snap_vol->snapshot = snap; - ret = glusterd_gen_snap_volfiles (snap_vol, peer_snap_name); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to generate snap vol files " - "for snap %s", peer_snap_name); - goto out; + if (!strcmp(server, "glustershd") || + !strcmp(server, "nfs") || + !strcmp(server, "quotad")) { + ret = dict_set_str(options, "transport.socket.ignore-enoent", "on"); + if (ret) + goto out; } - ret = glusterd_import_quota_conf (peer_data, i, - snap_vol, prefix); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to import quota conf " - "for snap %s", peer_snap_name); + ret = glusterd_rpc_create (&rpc, options, + glusterd_nodesvc_rpc_notify, + server); + if (ret) goto out; - } - - snap_vol = NULL; + (void) glusterd_nodesvc_set_rpc (server, rpc); } +out: + return ret; +} - ret = glusterd_store_snap (snap); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Could not store snap" - "object %s", peer_snap_name); - goto out; - } +int32_t +glusterd_nodesvc_disconnect (char *server) +{ + struct rpc_clnt *rpc = NULL; + glusterd_conf_t *priv = THIS->private; -out: - if (ret) - glusterd_snap_remove (dict, snap, - _gf_true, _gf_true); + rpc = glusterd_nodesvc_get_rpc (server); + (void)glusterd_nodesvc_set_rpc (server, NULL); - if (dict) - dict_unref (dict); + if (rpc) + glusterd_rpc_clnt_unref (priv, rpc); - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; + return 0; } -/* During a peer-handshake, after the volumes have synced, and the list of - * missed snapshots have synced, the node will perform the pending deletes - * and restores on this list. At this point, the current snapshot list in - * the node will be updated, and hence in case of conflicts arising during - * snapshot handshake, the peer hosting the bricks will be given precedence - * Likewise, if there will be a conflict, and both peers will be in the same - * state, i.e either both would be hosting bricks or both would not be hosting - * bricks, then a decision can't be taken and a peer-reject will happen. - * - * glusterd_compare_and_update_snap() implements the following algorithm to - * perform the above task: - * Step 1: Start. - * Step 2: Check if the peer is missing a delete or restore on the said snap. - * If yes, goto step 6. - * Step 3: Check if there is a conflict between the peer's data and the - * local snap. If no, goto step 5. - * Step 4: As there is a conflict, check if both the peer and the local nodes - * are hosting bricks. Based on the results perform the following: - * Peer Hosts Bricks Local Node Hosts Bricks Action - * Yes Yes Goto Step 7 - * No No Goto Step 7 - * Yes No Goto Step 8 - * No Yes Goto Step 6 - * Step 5: Check if the local node is missing the peer's data. - * If yes, goto step 9. - * Step 6: It's a no-op. Goto step 10 - * Step 7: Peer Reject. Goto step 10 - * Step 8: Delete local node's data. - * Step 9: Accept Peer Data. - * Step 10: Stop - * - */ int32_t -glusterd_compare_and_update_snap (dict_t *peer_data, int32_t snap_count, - glusterd_peerinfo_t *peerinfo) -{ - char buf[NAME_MAX] = ""; - char prefix[NAME_MAX] = ""; - char *peer_snap_name = NULL; - char *peer_snap_id = NULL; - dict_t *dict = NULL; - glusterd_snap_t *snap = NULL; - gf_boolean_t conflict = _gf_false; - gf_boolean_t is_local = _gf_false; - gf_boolean_t is_hosted = _gf_false; - gf_boolean_t missed_delete = _gf_false; - int32_t ret = -1; - xlator_t *this = NULL; +glusterd_nodesvc_start (char *server, gf_boolean_t wait) +{ + int32_t ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + runner_t runner = {0,}; + char pidfile[PATH_MAX] = {0,}; + char logfile[PATH_MAX] = {0,}; + char volfile[PATH_MAX] = {0,}; + char rundir[PATH_MAX] = {0,}; + char sockfpath[PATH_MAX] = {0,}; + char *volfileserver = NULL; + char volfileid[256] = {0}; + char glusterd_uuid_option[1024] = {0}; + char valgrind_logfile[PATH_MAX] = {0}; this = THIS; - GF_ASSERT (this); - GF_ASSERT (peer_data); - GF_ASSERT (peerinfo); + GF_ASSERT(this); - snprintf (prefix, sizeof(prefix), "snap%d", snap_count); + priv = this->private; - /* Fetch the peer's snapname */ - snprintf (buf, sizeof(buf), "%s.snapname", prefix); - ret = dict_get_str (peer_data, buf, &peer_snap_name); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to fetch snapname from peer: %s", - peerinfo->hostname); + glusterd_get_nodesvc_rundir (server, priv->workdir, + rundir, sizeof (rundir)); + ret = mkdir (rundir, 0777); + + if ((ret == -1) && (EEXIST != errno)) { + gf_log ("", GF_LOG_ERROR, "Unable to create rundir %s", + rundir); goto out; } - /* Fetch the peer's snap_id */ - snprintf (buf, sizeof(buf), "%s.snap_id", prefix); - ret = dict_get_str (peer_data, buf, &peer_snap_id); + glusterd_get_nodesvc_pidfile (server, priv->workdir, + pidfile, sizeof (pidfile)); + glusterd_get_nodesvc_volfile (server, priv->workdir, + volfile, sizeof (volfile)); + ret = access (volfile, F_OK); if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to fetch snap_id from peer: %s", - peerinfo->hostname); + gf_log ("", GF_LOG_ERROR, "%s Volfile %s is not present", + server, volfile); goto out; } - /* Check if the peer has missed a snap delete or restore - * resulting in stale data for the snap in question - */ - missed_delete = glusterd_peer_has_missed_snap_delete (peerinfo, - peer_snap_id); - if (missed_delete == _gf_true) { - /* Peer has missed delete on the missing/conflicting snap_id */ - gf_log (this->name, GF_LOG_INFO, "Peer %s has missed a delete " - "on snap %s", peerinfo->hostname, peer_snap_name); - ret = 0; - goto out; - } + snprintf (logfile, PATH_MAX, "%s/%s.log", DEFAULT_LOG_FILE_DIRECTORY, + server); + snprintf (volfileid, sizeof (volfileid), "gluster/%s", server); - /* Check if there is a conflict, and if the - * peer data is already present - */ - glusterd_is_peer_snap_conflicting (peer_snap_name, peer_snap_id, - &conflict, &snap, - peerinfo->hostname); - if (conflict == _gf_false) { - if (snap) { - /* Peer has snap with the same snapname - * and snap_id. No need to accept peer data - */ - ret = 0; - goto out; - } else { - /* Peer has snap with the same snapname - * and snap_id, which local node doesn't have. - */ - goto accept_peer_data; - } + if (dict_get_str (this->options, "transport.socket.bind-address", + &volfileserver) != 0) { + volfileserver = "localhost"; } - /* There is a conflict. Check if the current node is - * hosting bricks for the conflicted snap. - */ - is_local = glusterd_are_snap_bricks_local (snap); - - /* Check if the peer is hosting any bricks for the - * conflicting snap - */ - snprintf (buf, sizeof(buf), "%s.host_bricks", prefix); - ret = dict_get_int8 (peer_data, buf, (int8_t *) &is_hosted); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to fetch host_bricks from peer: %s " - "for %s", peerinfo->hostname, peer_snap_name); - goto out; - } + glusterd_nodesvc_set_socket_filepath (rundir, MY_UUID, + sockfpath, sizeof (sockfpath)); - /* As there is a conflict at this point of time, the data of the - * node that hosts a brick takes precedence. If both the local - * node and the peer are in the same state, i.e if both of them - * are either hosting or not hosting the bricks, for the snap, - * then it's a peer reject - */ - if (is_hosted == is_local) { - gf_log (this->name, GF_LOG_ERROR, - "Conflict in snapshot %s with peer %s", - peer_snap_name, peerinfo->hostname); - ret = -1; - goto out; - } + if (gf_is_service_running(pidfile, NULL)) + goto connect; - if (is_hosted == _gf_false) { - /* If there was a conflict, and the peer is not hosting - * any brick, then don't accept peer data - */ - gf_log (this->name, GF_LOG_DEBUG, - "Peer doesn't hosts bricks for conflicting " - "snap(%s). Not accepting peer data.", - peer_snap_name); - ret = 0; - goto out; - } + runinit (&runner); - /* The peer is hosting a brick in case of conflict - * And local node isn't. Hence remove local node's - * data and accept peer data - */ + if (priv->valgrind) { + snprintf (valgrind_logfile, PATH_MAX, + "%s/valgrind-%s.log", + DEFAULT_LOG_FILE_DIRECTORY, + server); - gf_log (this->name, GF_LOG_DEBUG, "Peer hosts bricks for conflicting " - "snap(%s). Removing local data. Accepting peer data.", - peer_snap_name); + runner_add_args (&runner, "valgrind", "--leak-check=full", + "--trace-children=yes", "--track-origins=yes", + NULL); + runner_argprintf (&runner, "--log-file=%s", valgrind_logfile); + } - dict = dict_new(); - if (!dict) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to create dict"); - ret = -1; - goto out; - } + runner_add_args (&runner, SBIN_DIR"/glusterfs", + "-s", volfileserver, + "--volfile-id", volfileid, + "-p", pidfile, + "-l", logfile, + "-S", sockfpath, + NULL); - ret = glusterd_snap_remove (dict, snap, _gf_true, _gf_false); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to remove snap %s", snap->snapname); - goto out; + if (!strcmp (server, "glustershd")) { + snprintf (glusterd_uuid_option, sizeof (glusterd_uuid_option), + "*replicate*.node-uuid=%s", uuid_utoa (MY_UUID)); + runner_add_args (&runner, "--xlator-option", + glusterd_uuid_option, NULL); } - -accept_peer_data: - - /* Accept Peer Data */ - ret = glusterd_import_friend_snap (peer_data, snap_count, - peer_snap_name, peer_snap_id); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to import snap %s from peer %s", - peer_snap_name, peerinfo->hostname); - goto out; + if (!strcmp (server, "quotad")) { + runner_add_args (&runner, "--xlator-option", + "*replicate*.data-self-heal=off", + "--xlator-option", + "*replicate*.metadata-self-heal=off", + "--xlator-option", + "*replicate*.entry-self-heal=off", NULL); } + runner_log (&runner, "", GF_LOG_DEBUG, + "Starting the nfs/glustershd services"); -out: - if (dict) - dict_unref (dict); - - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -/* Compare snapshots present in peer_data, with the snapshots in - * the current node - */ -int32_t -glusterd_compare_friend_snapshots (dict_t *peer_data, - glusterd_peerinfo_t *peerinfo) -{ - int32_t ret = -1; - int32_t snap_count = 0; - int i = 1; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (peer_data); - GF_ASSERT (peerinfo); - - ret = dict_get_int32 (peer_data, "snap_count", &snap_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to fetch snap_count"); - goto out; - } - - for (i = 1; i <= snap_count; i++) { - /* Compare one snapshot from peer_data at a time */ - ret = glusterd_compare_and_update_snap (peer_data, i, peerinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to compare snapshots with peer %s", - peerinfo->hostname); - goto out; + if (!wait) { + ret = runner_run_nowait (&runner); + } else { + synclock_unlock (&priv->big_lock); + { + ret = runner_run (&runner); } + synclock_lock (&priv->big_lock); + } +connect: + if (ret == 0) { + glusterd_nodesvc_connect (server, sockfpath); } - out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); return ret; } -int32_t -glusterd_compare_friend_data (dict_t *peer_data, int32_t *status, - char *hostname) +int +glusterd_nfs_server_start () { - int32_t ret = -1; - int32_t count = 0; - int i = 1; - gf_boolean_t update = _gf_false; - gf_boolean_t stale_nfs = _gf_false; - gf_boolean_t stale_shd = _gf_false; - gf_boolean_t stale_qd = _gf_false; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (peer_data); - GF_ASSERT (status); - - ret = glusterd_import_global_opts (peer_data); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Importing global " - "options failed"); - goto out; - } - - ret = dict_get_int32 (peer_data, "count", &count); - if (ret) - goto out; - - while (i <= count) { - ret = glusterd_compare_friend_volume (peer_data, i, status, - hostname); - if (ret) - goto out; - - if (GLUSTERD_VOL_COMP_RJT == *status) { - ret = 0; - goto out; - } - if (GLUSTERD_VOL_COMP_UPDATE_REQ == *status) - update = _gf_true; - - i++; - } - - if (update) { - if (glusterd_is_nodesvc_running ("nfs")) - stale_nfs = _gf_true; - if (glusterd_is_nodesvc_running ("glustershd")) - stale_shd = _gf_true; - if (glusterd_is_nodesvc_running ("quotad")) - stale_qd = _gf_true; - ret = glusterd_import_friend_volumes (peer_data); - if (ret) - goto out; - if (_gf_false == glusterd_are_all_volumes_stopped ()) { - ret = glusterd_nodesvcs_handle_graph_change (NULL); - } else { - if (stale_nfs) - glusterd_nfs_server_stop (); - if (stale_shd) - glusterd_shd_stop (); - if (stale_qd) - glusterd_quotad_stop (); - } - } - -out: - gf_log (this->name, GF_LOG_DEBUG, - "Returning with ret: %d, status: %d", ret, *status); - return ret; + return glusterd_nodesvc_start ("nfs", _gf_false); } -void -glusterd_get_nodesvc_dir (char *server, char *workdir, - char *path, size_t len) +int +glusterd_shd_start () { - GF_ASSERT (len == PATH_MAX); - snprintf (path, len, "%s/%s", workdir, server); + return glusterd_nodesvc_start ("glustershd", _gf_false); } -void -glusterd_get_nodesvc_rundir (char *server, char *workdir, - char *path, size_t len) +int +glusterd_quotad_start () { - char dir[PATH_MAX] = {0}; - GF_ASSERT (len == PATH_MAX); - - glusterd_get_nodesvc_dir (server, workdir, dir, sizeof (dir)); - snprintf (path, len, "%s/run", dir); + return glusterd_nodesvc_start ("quotad", _gf_false); } -void -glusterd_get_nodesvc_pidfile (char *server, char *workdir, - char *path, size_t len) +int +glusterd_quotad_start_wait () { - char dir[PATH_MAX] = {0}; - GF_ASSERT (len == PATH_MAX); - - glusterd_get_nodesvc_rundir (server, workdir, dir, sizeof (dir)); - snprintf (path, len, "%s/%s.pid", dir, server); + return glusterd_nodesvc_start ("quotad", _gf_true); } -void -glusterd_get_nodesvc_volfile (char *server, char *workdir, - char *volfile, size_t len) +gf_boolean_t +glusterd_is_nodesvc_running (char *server) { - char dir[PATH_MAX] = {0,}; - GF_ASSERT (len == PATH_MAX); + char pidfile[PATH_MAX] = {0,}; + glusterd_conf_t *priv = THIS->private; - glusterd_get_nodesvc_dir (server, workdir, dir, sizeof (dir)); - if (strcmp ("quotad", server) != 0) - snprintf (volfile, len, "%s/%s-server.vol", dir, server); - else - snprintf (volfile, len, "%s/%s.vol", dir, server); + glusterd_get_nodesvc_pidfile (server, priv->workdir, + pidfile, sizeof (pidfile)); + return gf_is_service_running (pidfile, NULL); } -void -glusterd_nodesvc_set_online_status (char *server, gf_boolean_t status) +int32_t +glusterd_unlink_file (char *sockfpath) { - glusterd_conf_t *priv = NULL; + int ret = 0; - GF_ASSERT (server); - priv = THIS->private; - GF_ASSERT (priv); - GF_ASSERT (priv->shd); - GF_ASSERT (priv->nfs); - GF_ASSERT (priv->quotad); + ret = unlink (sockfpath); + if (ret) { + if (ENOENT == errno) + ret = 0; + else + gf_log (THIS->name, GF_LOG_ERROR, "Failed to remove %s" + " error: %s", sockfpath, strerror (errno)); + } - if (!strcmp("glustershd", server)) - priv->shd->online = status; - else if (!strcmp ("nfs", server)) - priv->nfs->online = status; - else if (!strcmp ("quotad", server)) - priv->quotad->online = status; + return ret; } -gf_boolean_t -glusterd_is_nodesvc_online (char *server) +int32_t +glusterd_nodesvc_unlink_socket_file (char *server) { - glusterd_conf_t *conf = NULL; - gf_boolean_t online = _gf_false; + char sockfpath[PATH_MAX] = {0,}; + char rundir[PATH_MAX] = {0,}; + glusterd_conf_t *priv = THIS->private; - GF_ASSERT (server); - conf = THIS->private; - GF_ASSERT (conf); - GF_ASSERT (conf->shd); - GF_ASSERT (conf->nfs); - GF_ASSERT (conf->quotad); + glusterd_get_nodesvc_rundir (server, priv->workdir, + rundir, sizeof (rundir)); - if (!strcmp (server, "glustershd")) - online = conf->shd->online; - else if (!strcmp (server, "nfs")) - online = conf->nfs->online; - else if (!strcmp (server, "quotad")) - online = conf->quotad->online; + glusterd_nodesvc_set_socket_filepath (rundir, MY_UUID, + sockfpath, sizeof (sockfpath)); - return online; + return glusterd_unlink_file (sockfpath); } int32_t -glusterd_nodesvc_set_socket_filepath (char *rundir, uuid_t uuid, - char *socketpath, int len) +glusterd_nodesvc_stop (char *server, int sig) { - char sockfilepath[PATH_MAX] = {0,}; + char pidfile[PATH_MAX] = {0,}; + glusterd_conf_t *priv = THIS->private; + int ret = 0; - snprintf (sockfilepath, sizeof (sockfilepath), "%s/run-%s", - rundir, uuid_utoa (uuid)); + if (!glusterd_is_nodesvc_running (server)) + goto out; - glusterd_set_socket_filepath (sockfilepath, socketpath, len); - return 0; + (void)glusterd_nodesvc_disconnect (server); + + glusterd_get_nodesvc_pidfile (server, priv->workdir, + pidfile, sizeof (pidfile)); + ret = glusterd_service_stop (server, pidfile, sig, _gf_true); + + if (ret == 0) { + glusterd_nodesvc_set_online_status (server, _gf_false); + (void)glusterd_nodesvc_unlink_socket_file (server); + } +out: + return ret; } -struct rpc_clnt* -glusterd_pending_node_get_rpc (glusterd_pending_node_t *pending_node) +void +glusterd_nfs_pmap_deregister () { - struct rpc_clnt *rpc = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - nodesrv_t *shd = NULL; - glusterd_volinfo_t *volinfo = NULL; - nodesrv_t *nfs = NULL; - nodesrv_t *quotad = NULL; - glusterd_snapd_t *snapd = NULL; + if (pmap_unset (MOUNT_PROGRAM, MOUNTV3_VERSION)) + gf_log ("", GF_LOG_INFO, "De-registered MOUNTV3 successfully"); + else + gf_log ("", GF_LOG_ERROR, "De-register MOUNTV3 is unsuccessful"); - GF_VALIDATE_OR_GOTO (THIS->name, pending_node, out); - GF_VALIDATE_OR_GOTO (THIS->name, pending_node->node, out); + if (pmap_unset (MOUNT_PROGRAM, MOUNTV1_VERSION)) + gf_log ("", GF_LOG_INFO, "De-registered MOUNTV1 successfully"); + else + gf_log ("", GF_LOG_ERROR, "De-register MOUNTV1 is unsuccessful"); - if (pending_node->type == GD_NODE_BRICK) { - brickinfo = pending_node->node; - rpc = brickinfo->rpc; + if (pmap_unset (NFS_PROGRAM, NFSV3_VERSION)) + gf_log ("", GF_LOG_INFO, "De-registered NFSV3 successfully"); + else + gf_log ("", GF_LOG_ERROR, "De-register NFSV3 is unsuccessful"); - } else if (pending_node->type == GD_NODE_SHD) { - shd = pending_node->node; - rpc = shd->rpc; + if (pmap_unset (NLM_PROGRAM, NLMV4_VERSION)) + gf_log ("", GF_LOG_INFO, "De-registered NLM v4 successfully"); + else + gf_log ("", GF_LOG_ERROR, "De-registration of NLM v4 failed"); - } else if (pending_node->type == GD_NODE_REBALANCE) { - volinfo = pending_node->node; - if (volinfo->rebal.defrag) - rpc = volinfo->rebal.defrag->rpc; + if (pmap_unset (NLM_PROGRAM, NLMV1_VERSION)) + gf_log ("", GF_LOG_INFO, "De-registered NLM v1 successfully"); + else + gf_log ("", GF_LOG_ERROR, "De-registration of NLM v1 failed"); - } else if (pending_node->type == GD_NODE_NFS) { - nfs = pending_node->node; - rpc = nfs->rpc; + if (pmap_unset (ACL_PROGRAM, ACLV3_VERSION)) + gf_log ("", GF_LOG_INFO, "De-registered ACL v3 successfully"); + else + gf_log ("", GF_LOG_ERROR, "De-registration of ACL v3 failed"); +} - } else if (pending_node->type == GD_NODE_QUOTAD) { - quotad = pending_node->node; - rpc = quotad->rpc; - } else if (pending_node->type == GD_NODE_SNAPD) { - snapd = pending_node->node; - rpc = snapd->rpc; - } else { - GF_ASSERT (0); - } +int +glusterd_nfs_server_stop () +{ + int ret = 0; + gf_boolean_t deregister = _gf_false; + if (glusterd_is_nodesvc_running ("nfs")) + deregister = _gf_true; + ret = glusterd_nodesvc_stop ("nfs", SIGKILL); + if (ret) + goto out; + if (deregister) + glusterd_nfs_pmap_deregister (); out: - return rpc; + return ret; } -static inline struct rpc_clnt* -glusterd_snapd_get_rpc (glusterd_volinfo_t *volinfo) +int +glusterd_shd_stop () { - return volinfo->snapd.rpc; + return glusterd_nodesvc_stop ("glustershd", SIGTERM); } -struct rpc_clnt* -glusterd_nodesvc_get_rpc (char *server) +int +glusterd_quotad_stop () { - glusterd_conf_t *priv = NULL; - struct rpc_clnt *rpc = NULL; + return glusterd_nodesvc_stop ("quotad", SIGTERM); +} - GF_ASSERT (server); - priv = THIS->private; - GF_ASSERT (priv); - GF_ASSERT (priv->shd); - GF_ASSERT (priv->nfs); - GF_ASSERT (priv->quotad); +int +glusterd_add_node_to_dict (char *server, dict_t *dict, int count, + dict_t *vol_opts) +{ + int ret = -1; + glusterd_conf_t *priv = THIS->private; + char pidfile[PATH_MAX] = {0,}; + gf_boolean_t running = _gf_false; + int pid = -1; + int port = 0; + char key[1024] = {0,}; - if (!strcmp (server, "glustershd")) - rpc = priv->shd->rpc; - else if (!strcmp (server, "nfs")) - rpc = priv->nfs->rpc; + glusterd_get_nodesvc_pidfile (server, priv->workdir, pidfile, + sizeof (pidfile)); + //Consider service to be running only when glusterd sees it Online + if (glusterd_is_nodesvc_online (server)) + running = gf_is_service_running (pidfile, &pid); + + /* For nfs-servers/self-heal-daemon setting + * brick.hostname = "NFS Server" / "Self-heal Daemon" + * brick.path = uuid + * brick.port = 0 + * + * This might be confusing, but cli displays the name of + * the brick as hostname+path, so this will make more sense + * when output. + */ + snprintf (key, sizeof (key), "brick%d.hostname", count); + if (!strcmp (server, "nfs")) + ret = dict_set_str (dict, key, "NFS Server"); + else if (!strcmp (server, "glustershd")) + ret = dict_set_str (dict, key, "Self-heal Daemon"); else if (!strcmp (server, "quotad")) - rpc = priv->quotad->rpc; + ret = dict_set_str (dict, key, "Quota Daemon"); + if (ret) + goto out; - return rpc; -} + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.path", count); + ret = dict_set_dynstr (dict, key, gf_strdup (uuid_utoa (MY_UUID))); + if (ret) + goto out; -int32_t -glusterd_nodesvc_set_rpc (char *server, struct rpc_clnt *rpc) -{ - int ret = 0; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.port", count); + /* Port is available only for the NFS server. + * Self-heal daemon doesn't provide any port for access + * by entities other than gluster. + */ + if (!strcmp (server, "nfs")) { + if (dict_get (vol_opts, "nfs.port")) { + ret = dict_get_int32 (vol_opts, "nfs.port", &port); + if (ret) + goto out; + } else + port = GF_NFS3_PORT; + } + ret = dict_set_int32 (dict, key, port); + if (ret) + goto out; - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - GF_ASSERT (priv->shd); - GF_ASSERT (priv->nfs); - GF_ASSERT (priv->quotad); + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.pid", count); + ret = dict_set_int32 (dict, key, pid); + if (ret) + goto out; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.status", count); + ret = dict_set_int32 (dict, key, running); + if (ret) + goto out; - if (!strcmp ("glustershd", server)) - priv->shd->rpc = rpc; - else if (!strcmp ("nfs", server)) - priv->nfs->rpc = rpc; - else if (!strcmp ("quotad", server)) - priv->quotad->rpc = rpc; +out: + gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } -int32_t -glusterd_nodesvc_connect (char *server, char *socketpath) +int +glusterd_remote_hostname_get (rpcsvc_request_t *req, char *remote_host, int len) { - int ret = 0; - dict_t *options = NULL; - struct rpc_clnt *rpc = NULL; - glusterd_conf_t *priv = THIS->private; - - rpc = glusterd_nodesvc_get_rpc (server); + GF_ASSERT (req); + GF_ASSERT (remote_host); + GF_ASSERT (req->trans); - if (rpc == NULL) { - /* Setting frame-timeout to 10mins (600seconds). - * Unix domain sockets ensures that the connection is reliable. - * The default timeout of 30mins used for unreliable network - * connections is too long for unix domain socket connections. - */ - ret = rpc_transport_unix_options_build (&options, socketpath, - 600); - if (ret) - goto out; + char *name = NULL; + char *hostname = NULL; + char *tmp_host = NULL; + int ret = 0; - if (!strcmp(server, "glustershd") || - !strcmp(server, "nfs") || - !strcmp(server, "quotad")) { - ret = dict_set_str(options, "transport.socket.ignore-enoent", "on"); - if (ret) - goto out; - } + name = req->trans->peerinfo.identifier; + tmp_host = gf_strdup (name); + if (tmp_host) + get_host_name (tmp_host, &hostname); - ret = glusterd_rpc_create (&rpc, options, - glusterd_nodesvc_rpc_notify, - server); - if (ret) - goto out; - (void) glusterd_nodesvc_set_rpc (server, rpc); + GF_ASSERT (hostname); + if (!hostname) { + memset (remote_host, 0, len); + ret = -1; + goto out; } + + strncpy (remote_host, hostname, strlen (hostname)); + + out: + GF_FREE (tmp_host); return ret; } -int32_t -glusterd_nodesvc_disconnect (char *server) +int +glusterd_check_generate_start_service (int (*create_volfile) (), + int (*stop) (), int (*start) ()) { - struct rpc_clnt *rpc = NULL; - glusterd_conf_t *priv = THIS->private; + int ret = -1; - rpc = glusterd_nodesvc_get_rpc (server); - (void)glusterd_nodesvc_set_rpc (server, NULL); + ret = create_volfile (); + if (ret) + goto out; - if (rpc) - glusterd_rpc_clnt_unref (priv, rpc); + ret = stop (); + if (ret) + goto out; - return 0; + ret = start (); +out: + return ret; } -int32_t -glusterd_nodesvc_start (char *server, gf_boolean_t wait) +int +glusterd_reconfigure_nodesvc (int (*create_volfile) ()) { - int32_t ret = -1; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - runner_t runner = {0,}; - char pidfile[PATH_MAX] = {0,}; - char logfile[PATH_MAX] = {0,}; - char volfile[PATH_MAX] = {0,}; - char rundir[PATH_MAX] = {0,}; - char sockfpath[PATH_MAX] = {0,}; - char *volfileserver = NULL; - char volfileid[256] = {0}; - char glusterd_uuid_option[1024] = {0}; - char valgrind_logfile[PATH_MAX] = {0}; + int ret = -1; - this = THIS; - GF_ASSERT(this); + ret = create_volfile (); + if (ret) + goto out; - priv = this->private; + ret = glusterd_fetchspec_notify (THIS); +out: + return ret; +} - glusterd_get_nodesvc_rundir (server, priv->workdir, - rundir, sizeof (rundir)); - ret = mkdir (rundir, 0777); +int +glusterd_reconfigure_shd () +{ + int (*create_volfile) () = glusterd_create_shd_volfile; + return glusterd_reconfigure_nodesvc (create_volfile); +} - if ((ret == -1) && (EEXIST != errno)) { - gf_log ("", GF_LOG_ERROR, "Unable to create rundir %s", - rundir); +int +glusterd_reconfigure_quotad () +{ + return glusterd_reconfigure_nodesvc (glusterd_create_quotad_volfile); +} + +int +glusterd_reconfigure_nfs () +{ + int ret = -1; + gf_boolean_t identical = _gf_false; + + /* + * Check both OLD and NEW volfiles, if they are SAME by size + * and cksum i.e. "character-by-character". If YES, then + * NOTHING has been changed, just return. + */ + ret = glusterd_check_nfs_volfile_identical (&identical); + if (ret) goto out; - } - glusterd_get_nodesvc_pidfile (server, priv->workdir, - pidfile, sizeof (pidfile)); - glusterd_get_nodesvc_volfile (server, priv->workdir, - volfile, sizeof (volfile)); - ret = access (volfile, F_OK); - if (ret) { - gf_log ("", GF_LOG_ERROR, "%s Volfile %s is not present", - server, volfile); + if (identical) { + ret = 0; goto out; } - snprintf (logfile, PATH_MAX, "%s/%s.log", DEFAULT_LOG_FILE_DIRECTORY, - server); - snprintf (volfileid, sizeof (volfileid), "gluster/%s", server); + /* + * They are not identical. Find out if the topology is changed + * OR just the volume options. If just the options which got + * changed, then inform the xlator to reconfigure the options. + */ + identical = _gf_false; /* RESET the FLAG */ + ret = glusterd_check_nfs_topology_identical (&identical); + if (ret) + goto out; - if (dict_get_str (this->options, "transport.socket.bind-address", - &volfileserver) != 0) { - volfileserver = "localhost"; + /* Topology is not changed, but just the options. But write the + * options to NFS volfile, so that NFS will be reconfigured. + */ + if (identical) { + ret = glusterd_create_nfs_volfile(); + if (ret == 0) {/* Only if above PASSES */ + ret = glusterd_fetchspec_notify (THIS); + } + goto out; } - glusterd_nodesvc_set_socket_filepath (rundir, MY_UUID, - sockfpath, sizeof (sockfpath)); - - if (gf_is_service_running(pidfile, NULL)) - goto connect; - - runinit (&runner); - - if (priv->valgrind) { - snprintf (valgrind_logfile, PATH_MAX, - "%s/valgrind-%s.log", - DEFAULT_LOG_FILE_DIRECTORY, - server); - - runner_add_args (&runner, "valgrind", "--leak-check=full", - "--trace-children=yes", "--track-origins=yes", - NULL); - runner_argprintf (&runner, "--log-file=%s", valgrind_logfile); - } - - runner_add_args (&runner, SBIN_DIR"/glusterfs", - "-s", volfileserver, - "--volfile-id", volfileid, - "-p", pidfile, - "-l", logfile, - "-S", sockfpath, - NULL); - - if (!strcmp (server, "glustershd")) { - snprintf (glusterd_uuid_option, sizeof (glusterd_uuid_option), - "*replicate*.node-uuid=%s", uuid_utoa (MY_UUID)); - runner_add_args (&runner, "--xlator-option", - glusterd_uuid_option, NULL); - } - if (!strcmp (server, "quotad")) { - runner_add_args (&runner, "--xlator-option", - "*replicate*.data-self-heal=off", - "--xlator-option", - "*replicate*.metadata-self-heal=off", - "--xlator-option", - "*replicate*.entry-self-heal=off", NULL); - } - runner_log (&runner, "", GF_LOG_DEBUG, - "Starting the nfs/glustershd services"); + /* + * NFS volfile's topology has been changed. NFS server needs + * to be RESTARTED to ACT on the changed volfile. + */ + ret = glusterd_check_generate_start_nfs (); - if (!wait) { - ret = runner_run_nowait (&runner); - } else { - synclock_unlock (&priv->big_lock); - { - ret = runner_run (&runner); - } - synclock_lock (&priv->big_lock); - } -connect: - if (ret == 0) { - glusterd_nodesvc_connect (server, sockfpath); - } out: return ret; } int -glusterd_nfs_server_start () +glusterd_check_generate_start_nfs () { - return glusterd_nodesvc_start ("nfs", _gf_false); + int ret = 0; + + ret = glusterd_check_generate_start_service (glusterd_create_nfs_volfile, + glusterd_nfs_server_stop, + glusterd_nfs_server_start); + return ret; } int -glusterd_shd_start () +glusterd_check_generate_start_shd () { - return glusterd_nodesvc_start ("glustershd", _gf_false); + int ret = 0; + + ret = glusterd_check_generate_start_service (glusterd_create_shd_volfile, + glusterd_shd_stop, + glusterd_shd_start); + if (ret == -EINVAL) + ret = 0; + return ret; } int -glusterd_quotad_start () +glusterd_check_generate_start_quotad () { - return glusterd_nodesvc_start ("quotad", _gf_false); + int ret = 0; + + ret = glusterd_check_generate_start_service (glusterd_create_quotad_volfile, + glusterd_quotad_stop, + glusterd_quotad_start); + if (ret == -EINVAL) + ret = 0; + return ret; } +/* Blocking start variant of glusterd_check_generate_start_quotad */ int -glusterd_quotad_start_wait () +glusterd_check_generate_start_quotad_wait () { - return glusterd_nodesvc_start ("quotad", _gf_true); + int ret = 0; + + ret = glusterd_check_generate_start_service + (glusterd_create_quotad_volfile, glusterd_quotad_stop, + glusterd_quotad_start_wait); + if (ret == -EINVAL) + ret = 0; + return ret; } -gf_boolean_t -glusterd_is_nodesvc_running (char *server) -{ - char pidfile[PATH_MAX] = {0,}; - glusterd_conf_t *priv = THIS->private; +int +glusterd_nodesvcs_batch_op (glusterd_volinfo_t *volinfo, int (*nfs_op) (), + int (*shd_op) (), int (*qd_op) ()) + { + int ret = 0; + xlator_t *this = THIS; + glusterd_conf_t *conf = NULL; - glusterd_get_nodesvc_pidfile (server, priv->workdir, - pidfile, sizeof (pidfile)); - return gf_is_service_running (pidfile, NULL); -} + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); -int32_t -glusterd_unlink_file (char *sockfpath) -{ - int ret = 0; + ret = nfs_op (); + if (ret) + goto out; - ret = unlink (sockfpath); - if (ret) { - if (ENOENT == errno) - ret = 0; - else - gf_log (THIS->name, GF_LOG_ERROR, "Failed to remove %s" - " error: %s", sockfpath, strerror (errno)); + if (volinfo && !glusterd_is_volume_replicate (volinfo)) { + ; //do nothing + } else { + ret = shd_op (); + if (ret) + goto out; } - return ret; -} + if (conf->op_version == GD_OP_VERSION_MIN) + goto out; -int32_t -glusterd_nodesvc_unlink_socket_file (char *server) -{ - char sockfpath[PATH_MAX] = {0,}; - char rundir[PATH_MAX] = {0,}; - glusterd_conf_t *priv = THIS->private; + if (volinfo && !glusterd_is_volume_quota_enabled (volinfo)) + goto out; - glusterd_get_nodesvc_rundir (server, priv->workdir, - rundir, sizeof (rundir)); + ret = qd_op (); + if (ret) + goto out; - glusterd_nodesvc_set_socket_filepath (rundir, MY_UUID, - sockfpath, sizeof (sockfpath)); +out: + return ret; +} - return glusterd_unlink_file (sockfpath); +int +glusterd_nodesvcs_start (glusterd_volinfo_t *volinfo) +{ + return glusterd_nodesvcs_batch_op (volinfo, + glusterd_nfs_server_start, + glusterd_shd_start, + glusterd_quotad_start); } -int32_t -glusterd_nodesvc_stop (char *server, int sig) +int +glusterd_nodesvcs_stop (glusterd_volinfo_t *volinfo) { - char pidfile[PATH_MAX] = {0,}; - glusterd_conf_t *priv = THIS->private; - int ret = 0; - - if (!glusterd_is_nodesvc_running (server)) - goto out; + return glusterd_nodesvcs_batch_op (volinfo, + glusterd_nfs_server_stop, + glusterd_shd_stop, + glusterd_quotad_stop); +} - (void)glusterd_nodesvc_disconnect (server); +gf_boolean_t +glusterd_are_all_volumes_stopped () +{ + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + glusterd_volinfo_t *voliter = NULL; - glusterd_get_nodesvc_pidfile (server, priv->workdir, - pidfile, sizeof (pidfile)); - ret = glusterd_service_stop (server, pidfile, sig, _gf_true); + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); - if (ret == 0) { - glusterd_nodesvc_set_online_status (server, _gf_false); - (void)glusterd_nodesvc_unlink_socket_file (server); + list_for_each_entry (voliter, &priv->volumes, vol_list) { + if (voliter->status == GLUSTERD_STATUS_STARTED) + return _gf_false; } -out: - return ret; -} -void -glusterd_nfs_pmap_deregister () -{ - if (pmap_unset (MOUNT_PROGRAM, MOUNTV3_VERSION)) - gf_log ("", GF_LOG_INFO, "De-registered MOUNTV3 successfully"); - else - gf_log ("", GF_LOG_ERROR, "De-register MOUNTV3 is unsuccessful"); + return _gf_true; - if (pmap_unset (MOUNT_PROGRAM, MOUNTV1_VERSION)) - gf_log ("", GF_LOG_INFO, "De-registered MOUNTV1 successfully"); - else - gf_log ("", GF_LOG_ERROR, "De-register MOUNTV1 is unsuccessful"); +} - if (pmap_unset (NFS_PROGRAM, NFSV3_VERSION)) - gf_log ("", GF_LOG_INFO, "De-registered NFSV3 successfully"); - else - gf_log ("", GF_LOG_ERROR, "De-register NFSV3 is unsuccessful"); +gf_boolean_t +glusterd_all_replicate_volumes_stopped () +{ + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + glusterd_volinfo_t *voliter = NULL; - if (pmap_unset (NLM_PROGRAM, NLMV4_VERSION)) - gf_log ("", GF_LOG_INFO, "De-registered NLM v4 successfully"); - else - gf_log ("", GF_LOG_ERROR, "De-registration of NLM v4 failed"); + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); - if (pmap_unset (NLM_PROGRAM, NLMV1_VERSION)) - gf_log ("", GF_LOG_INFO, "De-registered NLM v1 successfully"); - else - gf_log ("", GF_LOG_ERROR, "De-registration of NLM v1 failed"); + list_for_each_entry (voliter, &priv->volumes, vol_list) { + if (!glusterd_is_volume_replicate (voliter)) + continue; + if (voliter->status == GLUSTERD_STATUS_STARTED) + return _gf_false; + } - if (pmap_unset (ACL_PROGRAM, ACLV3_VERSION)) - gf_log ("", GF_LOG_INFO, "De-registered ACL v3 successfully"); - else - gf_log ("", GF_LOG_ERROR, "De-registration of ACL v3 failed"); + return _gf_true; } -int -glusterd_nfs_server_stop () +gf_boolean_t +glusterd_all_volumes_with_quota_stopped () { - int ret = 0; - gf_boolean_t deregister = _gf_false; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + glusterd_volinfo_t *voliter = NULL; - if (glusterd_is_nodesvc_running ("nfs")) - deregister = _gf_true; - ret = glusterd_nodesvc_stop ("nfs", SIGKILL); - if (ret) - goto out; - if (deregister) - glusterd_nfs_pmap_deregister (); -out: - return ret; + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + list_for_each_entry (voliter, &priv->volumes, vol_list) { + if (!glusterd_is_volume_quota_enabled (voliter)) + continue; + if (voliter->status == GLUSTERD_STATUS_STARTED) + return _gf_false; + } + + return _gf_true; } + int -glusterd_shd_stop () +glusterd_nodesvcs_handle_graph_change (glusterd_volinfo_t *volinfo) { - return glusterd_nodesvc_stop ("glustershd", SIGTERM); + int (*shd_op) () = NULL; + int (*nfs_op) () = NULL; + int (*qd_op) () = NULL; + + if (volinfo && volinfo->is_snap_volume) + return 0; + + shd_op = glusterd_check_generate_start_shd; + nfs_op = glusterd_check_generate_start_nfs; + qd_op = glusterd_check_generate_start_quotad; + if (glusterd_are_all_volumes_stopped ()) { + shd_op = glusterd_shd_stop; + nfs_op = glusterd_nfs_server_stop; + qd_op = glusterd_quotad_stop; + } else { + if (glusterd_all_replicate_volumes_stopped()) { + shd_op = glusterd_shd_stop; + } + if (glusterd_all_volumes_with_quota_stopped ()) { + qd_op = glusterd_quotad_stop; + } + } + + return glusterd_nodesvcs_batch_op (volinfo, nfs_op, shd_op, qd_op); } int -glusterd_quotad_stop () +glusterd_nodesvcs_handle_reconfigure (glusterd_volinfo_t *volinfo) { - return glusterd_nodesvc_stop ("quotad", SIGTERM); + return glusterd_nodesvcs_batch_op (volinfo, + glusterd_reconfigure_nfs, + glusterd_reconfigure_shd, + glusterd_reconfigure_quotad); } int -glusterd_add_node_to_dict (char *server, dict_t *dict, int count, - dict_t *vol_opts) +glusterd_volume_count_get (void) { - int ret = -1; - glusterd_conf_t *priv = THIS->private; - char pidfile[PATH_MAX] = {0,}; - gf_boolean_t running = _gf_false; - int pid = -1; - int port = 0; - char key[1024] = {0,}; - - glusterd_get_nodesvc_pidfile (server, priv->workdir, pidfile, - sizeof (pidfile)); - //Consider service to be running only when glusterd sees it Online - if (glusterd_is_nodesvc_online (server)) - running = gf_is_service_running (pidfile, &pid); + glusterd_volinfo_t *tmp_volinfo = NULL; + int32_t ret = 0; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; - /* For nfs-servers/self-heal-daemon setting - * brick.hostname = "NFS Server" / "Self-heal Daemon" - * brick.path = uuid - * brick.port = 0 - * - * This might be confusing, but cli displays the name of - * the brick as hostname+path, so this will make more sense - * when output. - */ - snprintf (key, sizeof (key), "brick%d.hostname", count); - if (!strcmp (server, "nfs")) - ret = dict_set_str (dict, key, "NFS Server"); - else if (!strcmp (server, "glustershd")) - ret = dict_set_str (dict, key, "Self-heal Daemon"); - else if (!strcmp (server, "quotad")) - ret = dict_set_str (dict, key, "Quota Daemon"); - if (ret) - goto out; + this = THIS; + GF_ASSERT (this); - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d.path", count); - ret = dict_set_dynstr (dict, key, gf_strdup (uuid_utoa (MY_UUID))); - if (ret) - goto out; + priv = this->private; - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d.port", count); - /* Port is available only for the NFS server. - * Self-heal daemon doesn't provide any port for access - * by entities other than gluster. - */ - if (!strcmp (server, "nfs")) { - if (dict_get (vol_opts, "nfs.port")) { - ret = dict_get_int32 (vol_opts, "nfs.port", &port); - if (ret) - goto out; - } else - port = GF_NFS3_PORT; + list_for_each_entry (tmp_volinfo, &priv->volumes, vol_list) { + ret++; } - ret = dict_set_int32 (dict, key, port); - if (ret) - goto out; - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d.pid", count); - ret = dict_set_int32 (dict, key, pid); - if (ret) - goto out; - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d.status", count); - ret = dict_set_int32 (dict, key, running); - if (ret) - goto out; -out: - gf_log (THIS->name, GF_LOG_DEBUG, "Returning %d", ret); + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; + } int -glusterd_remote_hostname_get (rpcsvc_request_t *req, char *remote_host, int len) +glusterd_brickinfo_get (uuid_t uuid, char *hostname, char *path, + glusterd_brickinfo_t **brickinfo) { - GF_ASSERT (req); - GF_ASSERT (remote_host); - GF_ASSERT (req->trans); + glusterd_volinfo_t *volinfo = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + int ret = -1; - char *name = NULL; - char *hostname = NULL; - char *tmp_host = NULL; - int ret = 0; + GF_ASSERT (path); - name = req->trans->peerinfo.identifier; - tmp_host = gf_strdup (name); - if (tmp_host) - get_host_name (tmp_host, &hostname); + this = THIS; + GF_ASSERT (this); - GF_ASSERT (hostname); - if (!hostname) { - memset (remote_host, 0, len); - ret = -1; - goto out; - } - - strncpy (remote_host, hostname, strlen (hostname)); + priv = this->private; + list_for_each_entry (volinfo, &priv->volumes, vol_list) { + ret = glusterd_volume_brickinfo_get (uuid, hostname, path, + volinfo, brickinfo); + if (ret == 0) + /*Found*/ + goto out; + } out: - GF_FREE (tmp_host); return ret; } int -glusterd_check_generate_start_service (int (*create_volfile) (), - int (*stop) (), int (*start) ()) +glusterd_brick_start (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + gf_boolean_t wait) { - int ret = -1; - - ret = create_volfile (); - if (ret) - goto out; - - ret = stop (); - if (ret) - goto out; - - ret = start (); -out: - return ret; -} + int ret = -1; + xlator_t *this = NULL; -int -glusterd_reconfigure_nodesvc (int (*create_volfile) ()) -{ - int ret = -1; + this = THIS; + GF_ASSERT (this); - ret = create_volfile (); - if (ret) + if ((!brickinfo) || (!volinfo)) goto out; - ret = glusterd_fetchspec_notify (THIS); -out: - return ret; -} - -int -glusterd_reconfigure_shd () -{ - int (*create_volfile) () = glusterd_create_shd_volfile; - return glusterd_reconfigure_nodesvc (create_volfile); -} - -int -glusterd_reconfigure_quotad () -{ - return glusterd_reconfigure_nodesvc (glusterd_create_quotad_volfile); -} - -int -glusterd_reconfigure_nfs () -{ - int ret = -1; - gf_boolean_t identical = _gf_false; - - /* - * Check both OLD and NEW volfiles, if they are SAME by size - * and cksum i.e. "character-by-character". If YES, then - * NOTHING has been changed, just return. - */ - ret = glusterd_check_nfs_volfile_identical (&identical); - if (ret) - goto out; + if (uuid_is_null (brickinfo->uuid)) { + ret = glusterd_resolve_brick (brickinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK, + brickinfo->hostname, brickinfo->path); + goto out; + } + } - if (identical) { + if (uuid_compare (brickinfo->uuid, MY_UUID)) { ret = 0; goto out; } - - /* - * They are not identical. Find out if the topology is changed - * OR just the volume options. If just the options which got - * changed, then inform the xlator to reconfigure the options. - */ - identical = _gf_false; /* RESET the FLAG */ - ret = glusterd_check_nfs_topology_identical (&identical); - if (ret) - goto out; - - /* Topology is not changed, but just the options. But write the - * options to NFS volfile, so that NFS will be reconfigured. - */ - if (identical) { - ret = glusterd_create_nfs_volfile(); - if (ret == 0) {/* Only if above PASSES */ - ret = glusterd_fetchspec_notify (THIS); - } + ret = glusterd_volume_start_glusterfs (volinfo, brickinfo, wait); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Unable to start brick %s:%s", + brickinfo->hostname, brickinfo->path); goto out; } - /* - * NFS volfile's topology has been changed. NFS server needs - * to be RESTARTED to ACT on the changed volfile. - */ - ret = glusterd_check_generate_start_nfs (); - out: + gf_log (this->name, GF_LOG_DEBUG, "returning %d ", ret); return ret; } int -glusterd_check_generate_start_nfs () +glusterd_restart_bricks (glusterd_conf_t *conf) { - int ret = 0; + int ret = 0; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + glusterd_snap_t *snap = NULL; + gf_boolean_t start_nodesvcs = _gf_false; + xlator_t *this = NULL; - ret = glusterd_check_generate_start_service (glusterd_create_nfs_volfile, - glusterd_nfs_server_stop, - glusterd_nfs_server_start); - return ret; -} + this = THIS; + GF_ASSERT (this); -int -glusterd_check_generate_start_shd () -{ - int ret = 0; + list_for_each_entry (volinfo, &conf->volumes, vol_list) { + if (volinfo->status != GLUSTERD_STATUS_STARTED) + continue; + start_nodesvcs = _gf_true; + gf_log (this->name, GF_LOG_DEBUG, "starting the volume %s", + volinfo->volname); + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + glusterd_brick_start (volinfo, brickinfo, _gf_false); + } + } - ret = glusterd_check_generate_start_service (glusterd_create_shd_volfile, - glusterd_shd_stop, - glusterd_shd_start); - if (ret == -EINVAL) - ret = 0; - return ret; -} + list_for_each_entry (snap, &conf->snapshots, snap_list) { + list_for_each_entry (volinfo, &snap->volumes, vol_list) { + if (volinfo->status != GLUSTERD_STATUS_STARTED) + continue; + start_nodesvcs = _gf_true; + gf_log (this->name, GF_LOG_DEBUG, "starting the snap " + "volume %s", volinfo->volname); + list_for_each_entry (brickinfo, &volinfo->bricks, + brick_list) { + glusterd_brick_start (volinfo, brickinfo, + _gf_false); + } + } + } -int -glusterd_check_generate_start_quotad () -{ - int ret = 0; + if (start_nodesvcs) + glusterd_nodesvcs_handle_graph_change (NULL); - ret = glusterd_check_generate_start_service (glusterd_create_quotad_volfile, - glusterd_quotad_stop, - glusterd_quotad_start); - if (ret == -EINVAL) - ret = 0; return ret; } -/* Blocking start variant of glusterd_check_generate_start_quotad */ int -glusterd_check_generate_start_quotad_wait () +_local_gsyncd_start (dict_t *this, char *key, data_t *value, void *data) { - int ret = 0; - - ret = glusterd_check_generate_start_service - (glusterd_create_quotad_volfile, glusterd_quotad_stop, - glusterd_quotad_start_wait); - if (ret == -EINVAL) - ret = 0; - return ret; -} + char *path_list = NULL; + char *slave = NULL; + char *slave_url = NULL; + char *slave_vol = NULL; + char *slave_host = NULL; + char *statefile = NULL; + char buf[1024] = "faulty"; + int uuid_len = 0; + int ret = 0; + int op_ret = 0; + int ret_status = 0; + char uuid_str[64] = {0}; + glusterd_volinfo_t *volinfo = NULL; + char confpath[PATH_MAX] = ""; + char *op_errstr = NULL; + glusterd_conf_t *priv = NULL; + gf_boolean_t is_template_in_use = _gf_false; + gf_boolean_t is_paused = _gf_false; + char *key1 = NULL; + xlator_t *this1 = NULL; -int -glusterd_nodesvcs_batch_op (glusterd_volinfo_t *volinfo, int (*nfs_op) (), - int (*shd_op) (), int (*qd_op) ()) - { - int ret = 0; - xlator_t *this = THIS; - glusterd_conf_t *conf = NULL; + this1 = THIS; + GF_ASSERT (this1); + priv = this1->private; + GF_ASSERT (priv); + GF_ASSERT (data); - GF_ASSERT (this); - conf = this->private; - GF_ASSERT (conf); + volinfo = data; + slave = strchr(value->data, ':'); + if (slave) + slave ++; + else + return 0; + uuid_len = (slave - value->data - 1); - ret = nfs_op (); - if (ret) - goto out; + strncpy (uuid_str, (char*)value->data, uuid_len); - if (volinfo && !glusterd_is_volume_replicate (volinfo)) { - ; //do nothing - } else { - ret = shd_op (); - if (ret) - goto out; - } + /* Getting Local Brickpaths */ + ret = glusterd_get_local_brickpaths (volinfo, &path_list); - if (conf->op_version == GD_OP_VERSION_MIN) + /*Generating the conf file path needed by gsyncd */ + ret = glusterd_get_slave_info (slave, &slave_url, &slave_host, + &slave_vol, &op_errstr); + if (ret) { + gf_log (this1->name, GF_LOG_ERROR, + "Unable to fetch slave details."); + ret = -1; goto out; + } - if (volinfo && !glusterd_is_volume_quota_enabled (volinfo)) - goto out; + ret = snprintf (confpath, sizeof(confpath) - 1, + "%s/"GEOREP"/%s_%s_%s/gsyncd.conf", + priv->workdir, volinfo->volname, + slave_host, slave_vol); + confpath[ret] = '\0'; - ret = qd_op (); - if (ret) + /* Fetching the last status of the node */ + ret = glusterd_get_statefile_name (volinfo, slave, + confpath, &statefile, + &is_template_in_use); + if (ret) { + if (!strstr(slave, "::")) + gf_log (this1->name, GF_LOG_INFO, + "%s is not a valid slave url.", slave); + else + gf_log (this1->name, GF_LOG_INFO, "Unable to get" + " statefile's name"); goto out; + } -out: - return ret; -} - -int -glusterd_nodesvcs_start (glusterd_volinfo_t *volinfo) -{ - return glusterd_nodesvcs_batch_op (volinfo, - glusterd_nfs_server_start, - glusterd_shd_start, - glusterd_quotad_start); -} + /* If state-file entry is missing from the config file, + * do not start gsyncd on restart */ + if (is_template_in_use) { + gf_log (this1->name, GF_LOG_INFO, + "state-file entry is missing in config file." + "Not Restarting"); + goto out; + } -int -glusterd_nodesvcs_stop (glusterd_volinfo_t *volinfo) -{ - return glusterd_nodesvcs_batch_op (volinfo, - glusterd_nfs_server_stop, - glusterd_shd_stop, - glusterd_quotad_stop); -} + is_template_in_use = _gf_false; -gf_boolean_t -glusterd_are_all_volumes_stopped () -{ - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; - glusterd_volinfo_t *voliter = NULL; + ret = gsync_status (volinfo->volname, slave, confpath, + &ret_status, &is_template_in_use); + if (ret == -1) { + gf_log (this1->name, GF_LOG_INFO, + GEOREP" start option validation failed "); + ret = 0; + goto out; + } - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); + if (is_template_in_use == _gf_true) { + gf_log (this1->name, GF_LOG_INFO, + "pid-file entry is missing in config file." + "Not Restarting"); + ret = 0; + goto out; + } - list_for_each_entry (voliter, &priv->volumes, vol_list) { - if (voliter->status == GLUSTERD_STATUS_STARTED) - return _gf_false; + ret = glusterd_gsync_read_frm_status (statefile, buf, sizeof (buf)); + if (ret < 0) { + gf_log (this1->name, GF_LOG_ERROR, "Unable to read the status"); + goto out; } - return _gf_true; + /* Move the pointer two characters ahead to surpass '//' */ + if ((key1 = strchr (slave, '/'))) + key1 = key1 + 2; -} + /* Looks for the last status, to find if the sessiom was running + * when the node went down. If the session was not started or + * not started, do not restart the geo-rep session */ + if ((!strcmp (buf, "Not Started")) || + (!strcmp (buf, "Stopped"))) { + gf_log (this1->name, GF_LOG_INFO, + "Geo-Rep Session was not started between " + "%s and %s::%s. Not Restarting", volinfo->volname, + slave_url, slave_vol); + goto out; + } else if (strstr(buf, "Paused")) { + is_paused = _gf_true; + } else if ((!strcmp (buf, "Config Corrupted"))) { + gf_log (this1->name, GF_LOG_INFO, + "Recovering from a corrupted config. " + "Not Restarting. Use start (force) to " + "start the session between %s and %s::%s.", + volinfo->volname, + slave_url, slave_vol); + goto out; + } -gf_boolean_t -glusterd_all_replicate_volumes_stopped () -{ - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; - glusterd_volinfo_t *voliter = NULL; + if (is_paused) { + glusterd_start_gsync (volinfo, slave, path_list, confpath, + uuid_str, NULL, _gf_true); + } + else { + /* Add slave to the dict indicating geo-rep session is running*/ + ret = dict_set_dynstr_with_alloc (volinfo->gsync_active_slaves, + key1, "running"); + if (ret) { + gf_log (this1->name, GF_LOG_ERROR, "Unable to set key:%s" + " value:running in the dict", key1); + goto out; + } + ret = glusterd_start_gsync (volinfo, slave, path_list, confpath, + uuid_str, NULL, _gf_false); + if (ret) + dict_del (volinfo->gsync_active_slaves, key1); + } - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); +out: + if (statefile) + GF_FREE (statefile); - list_for_each_entry (voliter, &priv->volumes, vol_list) { - if (!glusterd_is_volume_replicate (voliter)) - continue; - if (voliter->status == GLUSTERD_STATUS_STARTED) - return _gf_false; + if (is_template_in_use) { + op_ret = glusterd_create_status_file (volinfo->volname, slave, + slave_host, slave_vol, + "Config Corrupted"); + if (op_ret) { + gf_log (this1->name, GF_LOG_ERROR, + "Unable to create status file" + ". Error : %s", strerror (errno)); + ret = op_ret; + } } - return _gf_true; + GF_FREE (path_list); + GF_FREE (op_errstr); + + return ret; } -gf_boolean_t -glusterd_all_volumes_with_quota_stopped () +int +glusterd_volume_restart_gsyncds (glusterd_volinfo_t *volinfo) { - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; - glusterd_volinfo_t *voliter = NULL; - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - - list_for_each_entry (voliter, &priv->volumes, vol_list) { - if (!glusterd_is_volume_quota_enabled (voliter)) - continue; - if (voliter->status == GLUSTERD_STATUS_STARTED) - return _gf_false; - } + GF_ASSERT (volinfo); - return _gf_true; + dict_foreach (volinfo->gsync_slaves, _local_gsyncd_start, volinfo); + return 0; } - int -glusterd_nodesvcs_handle_graph_change (glusterd_volinfo_t *volinfo) +glusterd_restart_gsyncds (glusterd_conf_t *conf) { - int (*shd_op) () = NULL; - int (*nfs_op) () = NULL; - int (*qd_op) () = NULL; - - if (volinfo && volinfo->is_snap_volume) - return 0; + glusterd_volinfo_t *volinfo = NULL; + int ret = 0; - shd_op = glusterd_check_generate_start_shd; - nfs_op = glusterd_check_generate_start_nfs; - qd_op = glusterd_check_generate_start_quotad; - if (glusterd_are_all_volumes_stopped ()) { - shd_op = glusterd_shd_stop; - nfs_op = glusterd_nfs_server_stop; - qd_op = glusterd_quotad_stop; - } else { - if (glusterd_all_replicate_volumes_stopped()) { - shd_op = glusterd_shd_stop; - } - if (glusterd_all_volumes_with_quota_stopped ()) { - qd_op = glusterd_quotad_stop; - } + list_for_each_entry (volinfo, &conf->volumes, vol_list) { + glusterd_volume_restart_gsyncds (volinfo); } - - return glusterd_nodesvcs_batch_op (volinfo, nfs_op, shd_op, qd_op); + return ret; } -int -glusterd_nodesvcs_handle_reconfigure (glusterd_volinfo_t *volinfo) +inline int +glusterd_get_dist_leaf_count (glusterd_volinfo_t *volinfo) { - return glusterd_nodesvcs_batch_op (volinfo, - glusterd_reconfigure_nfs, - glusterd_reconfigure_shd, - glusterd_reconfigure_quotad); + int rcount = volinfo->replica_count; + int scount = volinfo->stripe_count; + + if (volinfo->type == GF_CLUSTER_TYPE_DISPERSE) + return volinfo->disperse_count; + + return (rcount ? rcount : 1) * (scount ? scount : 1); } int -glusterd_volume_count_get (void) +glusterd_get_brickinfo (xlator_t *this, const char *brickname, int port, + gf_boolean_t localhost, glusterd_brickinfo_t **brickinfo) { - glusterd_volinfo_t *tmp_volinfo = NULL; - int32_t ret = 0; - xlator_t *this = NULL; glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; + glusterd_brickinfo_t *tmpbrkinfo = NULL; + int ret = -1; - this = THIS; + GF_ASSERT (brickname); GF_ASSERT (this); priv = this->private; - - list_for_each_entry (tmp_volinfo, &priv->volumes, vol_list) { - ret++; + list_for_each_entry (volinfo, &priv->volumes, vol_list) { + list_for_each_entry (tmpbrkinfo, &volinfo->bricks, + brick_list) { + if (localhost && !gf_is_local_addr (tmpbrkinfo->hostname)) + continue; + if (!strcmp(tmpbrkinfo->path, brickname) && + (tmpbrkinfo->port == port)) { + *brickinfo = tmpbrkinfo; + return 0; + } + } } - - - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; - } -int -glusterd_brickinfo_get (uuid_t uuid, char *hostname, char *path, - glusterd_brickinfo_t **brickinfo) +glusterd_brickinfo_t* +glusterd_get_brickinfo_by_position (glusterd_volinfo_t *volinfo, uint32_t pos) { - glusterd_volinfo_t *volinfo = NULL; - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; - int ret = -1; - - GF_ASSERT (path); - - this = THIS; - GF_ASSERT (this); - - priv = this->private; + glusterd_brickinfo_t *tmpbrkinfo = NULL; - list_for_each_entry (volinfo, &priv->volumes, vol_list) { + list_for_each_entry (tmpbrkinfo, &volinfo->bricks, + brick_list) { + if (pos == 0) + return tmpbrkinfo; + pos--; + } + return NULL; +} - ret = glusterd_volume_brickinfo_get (uuid, hostname, path, - volinfo, brickinfo); - if (ret == 0) - /*Found*/ - goto out; +void +glusterd_set_brick_status (glusterd_brickinfo_t *brickinfo, + gf_brick_status_t status) +{ + GF_ASSERT (brickinfo); + brickinfo->status = status; + if (GF_BRICK_STARTED == status) { + gf_log ("glusterd", GF_LOG_DEBUG, "Setting brick %s:%s status " + "to started", brickinfo->hostname, brickinfo->path); + } else { + gf_log ("glusterd", GF_LOG_DEBUG, "Setting brick %s:%s status " + "to stopped", brickinfo->hostname, brickinfo->path); } -out: - return ret; } -int -glusterd_brick_start (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo, - gf_boolean_t wait) +gf_boolean_t +glusterd_is_brick_started (glusterd_brickinfo_t *brickinfo) { - int ret = -1; - xlator_t *this = NULL; + GF_ASSERT (brickinfo); + return (brickinfo->status == GF_BRICK_STARTED); +} - this = THIS; - GF_ASSERT (this); +int +glusterd_friend_brick_belongs (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, void* uuid) +{ + int ret = -1; - if ((!brickinfo) || (!volinfo)) - goto out; + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + GF_ASSERT (uuid); if (uuid_is_null (brickinfo->uuid)) { ret = glusterd_resolve_brick (brickinfo); if (ret) { - gf_log (this->name, GF_LOG_ERROR, FMTSTR_RESOLVE_BRICK, - brickinfo->hostname, brickinfo->path); + GF_ASSERT (0); goto out; } } - - if (uuid_compare (brickinfo->uuid, MY_UUID)) { - ret = 0; - goto out; - } - ret = glusterd_volume_start_glusterfs (volinfo, brickinfo, wait); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to start brick %s:%s", - brickinfo->hostname, brickinfo->path); - goto out; - } - + if (!uuid_compare (brickinfo->uuid, *((uuid_t *)uuid))) + return 0; out: - gf_log (this->name, GF_LOG_DEBUG, "returning %d ", ret); - return ret; + return -1; } int -glusterd_restart_bricks (glusterd_conf_t *conf) +glusterd_get_brick_root (char *path, char **mount_point) { - int ret = 0; - glusterd_volinfo_t *volinfo = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - glusterd_snap_t *snap = NULL; - gf_boolean_t start_nodesvcs = _gf_false; - xlator_t *this = NULL; + char *ptr = NULL; + char *mnt_pt = NULL; + struct stat brickstat = {0}; + struct stat buf = {0}; - this = THIS; - GF_ASSERT (this); + if (!path) + goto err; + mnt_pt = gf_strdup (path); + if (!mnt_pt) + goto err; + if (stat (mnt_pt, &brickstat)) + goto err; - list_for_each_entry (volinfo, &conf->volumes, vol_list) { - if (volinfo->status != GLUSTERD_STATUS_STARTED) - continue; - start_nodesvcs = _gf_true; - gf_log (this->name, GF_LOG_DEBUG, "starting the volume %s", - volinfo->volname); - list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { - glusterd_brick_start (volinfo, brickinfo, _gf_false); + while ((ptr = strrchr (mnt_pt, '/')) && + ptr != mnt_pt) { + + *ptr = '\0'; + if (stat (mnt_pt, &buf)) { + gf_log (THIS->name, GF_LOG_ERROR, "error in " + "stat: %s", strerror (errno)); + goto err; + } + + if (brickstat.st_dev != buf.st_dev) { + *ptr = '/'; + break; } } - list_for_each_entry (snap, &conf->snapshots, snap_list) { - list_for_each_entry (volinfo, &snap->volumes, vol_list) { - if (volinfo->status != GLUSTERD_STATUS_STARTED) - continue; - start_nodesvcs = _gf_true; - gf_log (this->name, GF_LOG_DEBUG, "starting the snap " - "volume %s", volinfo->volname); - list_for_each_entry (brickinfo, &volinfo->bricks, - brick_list) { - glusterd_brick_start (volinfo, brickinfo, - _gf_false); - } + if (ptr == mnt_pt) { + if (stat ("/", &buf)) { + gf_log (THIS->name, GF_LOG_ERROR, "error in " + "stat: %s", strerror (errno)); + goto err; } + if (brickstat.st_dev == buf.st_dev) + strcpy (mnt_pt, "/"); } - if (start_nodesvcs) - glusterd_nodesvcs_handle_graph_change (NULL); + *mount_point = mnt_pt; + return 0; - return ret; + err: + GF_FREE (mnt_pt); + return -1; } -int -_local_gsyncd_start (dict_t *this, char *key, data_t *value, void *data) +static char* +glusterd_parse_inode_size (char *stream, char *pattern) { - char *path_list = NULL; - char *slave = NULL; - char *slave_url = NULL; - char *slave_vol = NULL; - char *slave_host = NULL; - char *statefile = NULL; - char buf[1024] = "faulty"; - int uuid_len = 0; - int ret = 0; - int op_ret = 0; - int ret_status = 0; - char uuid_str[64] = {0}; - glusterd_volinfo_t *volinfo = NULL; - char confpath[PATH_MAX] = ""; - char *op_errstr = NULL; - glusterd_conf_t *priv = NULL; - gf_boolean_t is_template_in_use = _gf_false; - gf_boolean_t is_paused = _gf_false; - char *key1 = NULL; - xlator_t *this1 = NULL; + char *needle = NULL; + char *trail = NULL; - this1 = THIS; - GF_ASSERT (this1); - priv = this1->private; - GF_ASSERT (priv); - GF_ASSERT (data); + needle = strstr (stream, pattern); + if (!needle) + goto out; - volinfo = data; - slave = strchr(value->data, ':'); - if (slave) - slave ++; - else - return 0; - uuid_len = (slave - value->data - 1); + needle = nwstrtail (needle, pattern); - strncpy (uuid_str, (char*)value->data, uuid_len); + trail = needle; + while (trail && isdigit (*trail)) trail++; + if (trail) + *trail = '\0'; - /* Getting Local Brickpaths */ - ret = glusterd_get_local_brickpaths (volinfo, &path_list); +out: + return needle; +} - /*Generating the conf file path needed by gsyncd */ - ret = glusterd_get_slave_info (slave, &slave_url, &slave_host, - &slave_vol, &op_errstr); - if (ret) { - gf_log (this1->name, GF_LOG_ERROR, - "Unable to fetch slave details."); - ret = -1; +static struct fs_info { + char *fs_type_name; + char *fs_tool_name; + char *fs_tool_arg; + char *fs_tool_pattern; + char *fs_tool_pkg; +} glusterd_fs[] = { + /* some linux have these in /usr/sbin/and others in /sbin/? */ + { "xfs", "xfs_info", NULL, "isize=", "xfsprogs" }, + { "ext3", "tune2fs", "-l", "Inode size:", "e2fsprogs" }, + { "ext4", "tune2fs", "-l", "Inode size:", "e2fsprogs" }, + { "btrfs", NULL, NULL, NULL, NULL }, + { NULL, NULL, NULL, NULL, NULL} +}; + +static int +glusterd_add_inode_size_to_dict (dict_t *dict, int count) +{ + int ret = -1; + char key[1024] = {0}; + char buffer[4096] = {0}; + char *inode_size = NULL; + char *device = NULL; + char *fs_name = NULL; + char *cur_word = NULL; + char *trail = NULL; + runner_t runner = {0, }; + struct fs_info *fs = NULL; + char fs_tool_name[256] = {0, }; + static dict_t *cached_fs = NULL; + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.device", count); + ret = dict_get_str (dict, key, &device); + if (ret) goto out; - } - ret = snprintf (confpath, sizeof(confpath) - 1, - "%s/"GEOREP"/%s_%s_%s/gsyncd.conf", - priv->workdir, volinfo->volname, - slave_host, slave_vol); - confpath[ret] = '\0'; + if (cached_fs) { + if (dict_get_str (cached_fs, device, &cur_word) == 0) { + goto cached; + } + } else { + cached_fs = dict_new (); + } - /* Fetching the last status of the node */ - ret = glusterd_get_statefile_name (volinfo, slave, - confpath, &statefile, - &is_template_in_use); - if (ret) { - if (!strstr(slave, "::")) - gf_log (this1->name, GF_LOG_INFO, - "%s is not a valid slave url.", slave); - else - gf_log (this1->name, GF_LOG_INFO, "Unable to get" - " statefile's name"); + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.fs_name", count); + ret = dict_get_str (dict, key, &fs_name); + if (ret) goto out; - } - /* If state-file entry is missing from the config file, - * do not start gsyncd on restart */ - if (is_template_in_use) { - gf_log (this1->name, GF_LOG_INFO, - "state-file entry is missing in config file." - "Not Restarting"); - goto out; - } + runinit (&runner); + runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); - is_template_in_use = _gf_false; + for (fs = glusterd_fs ; fs->fs_type_name; fs++) { + if (strcmp (fs_name, fs->fs_type_name) == 0) { + snprintf (fs_tool_name, sizeof (fs_tool_name), + "/usr/sbin/%s", fs->fs_tool_name); + if (access (fs_tool_name, R_OK|X_OK) == 0) + runner_add_arg (&runner, fs_tool_name); + else { + snprintf (fs_tool_name, sizeof (fs_tool_name), + "/sbin/%s", fs->fs_tool_name); + if (access (fs_tool_name, R_OK|X_OK) == 0) + runner_add_arg (&runner, fs_tool_name); + } + break; + } + } - ret = gsync_status (volinfo->volname, slave, confpath, - &ret_status, &is_template_in_use); - if (ret == -1) { - gf_log (this1->name, GF_LOG_INFO, - GEOREP" start option validation failed "); - ret = 0; + if (runner.argv[0]) { + if (fs->fs_tool_arg) + runner_add_arg (&runner, fs->fs_tool_arg); + runner_add_arg (&runner, device); + } else { + gf_log (THIS->name, GF_LOG_ERROR, "could not find %s to get" + "inode size for %s (%s): %s package missing?", + fs->fs_tool_name, device, fs_name, fs->fs_tool_pkg); goto out; } - if (is_template_in_use == _gf_true) { - gf_log (this1->name, GF_LOG_INFO, - "pid-file entry is missing in config file." - "Not Restarting"); - ret = 0; + ret = runner_start (&runner); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "failed to execute " + "\"%s\": %s", fs->fs_tool_name, strerror (errno)); + /* + * Runner_start might return an error after the child has + * been forked, e.g. if the program isn't there. In that + * case, we still need to call runner_end to reap the + * child and free resources. Fortunately, that seems to + * be harmless for other kinds of failures. + */ + (void) runner_end (&runner); goto out; } - ret = glusterd_gsync_read_frm_status (statefile, buf, sizeof (buf)); - if (ret < 0) { - gf_log (this1->name, GF_LOG_ERROR, "Unable to read the status"); - goto out; + for (;;) { + if (fgets (buffer, sizeof (buffer), + runner_chio (&runner, STDOUT_FILENO)) == NULL) + break; + trail = strrchr (buffer, '\n'); + if (trail) + *trail = '\0'; + + cur_word = + glusterd_parse_inode_size (buffer, fs->fs_tool_pattern); + + if (cur_word) + break; } - /* Move the pointer two characters ahead to surpass '//' */ - if ((key1 = strchr (slave, '/'))) - key1 = key1 + 2; + ret = runner_end (&runner); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, + "%s exited with non-zero exit status", + fs->fs_tool_name); - /* Looks for the last status, to find if the sessiom was running - * when the node went down. If the session was not started or - * not started, do not restart the geo-rep session */ - if ((!strcmp (buf, "Not Started")) || - (!strcmp (buf, "Stopped"))) { - gf_log (this1->name, GF_LOG_INFO, - "Geo-Rep Session was not started between " - "%s and %s::%s. Not Restarting", volinfo->volname, - slave_url, slave_vol); goto out; - } else if (strstr(buf, "Paused")) { - is_paused = _gf_true; - } else if ((!strcmp (buf, "Config Corrupted"))) { - gf_log (this1->name, GF_LOG_INFO, - "Recovering from a corrupted config. " - "Not Restarting. Use start (force) to " - "start the session between %s and %s::%s.", - volinfo->volname, - slave_url, slave_vol); + } + if (!cur_word) { + ret = -1; + gf_log (THIS->name, GF_LOG_ERROR, + "Unable to retrieve inode size using %s", + fs->fs_tool_name); goto out; } - if (is_paused) { - glusterd_start_gsync (volinfo, slave, path_list, confpath, - uuid_str, NULL, _gf_true); - } - else { - /* Add slave to the dict indicating geo-rep session is running*/ - ret = dict_set_dynstr_with_alloc (volinfo->gsync_active_slaves, - key1, "running"); - if (ret) { - gf_log (this1->name, GF_LOG_ERROR, "Unable to set key:%s" - " value:running in the dict", key1); - goto out; - } - ret = glusterd_start_gsync (volinfo, slave, path_list, confpath, - uuid_str, NULL, _gf_false); - if (ret) - dict_del (volinfo->gsync_active_slaves, key1); + if (dict_set_dynstr_with_alloc (cached_fs, device, cur_word)) { + /* not fatal if not entered into the cache */ + gf_log (THIS->name, GF_LOG_DEBUG, + "failed to cache fs inode size for %s", device); } -out: - if (statefile) - GF_FREE (statefile); - - if (is_template_in_use) { - op_ret = glusterd_create_status_file (volinfo->volname, slave, - slave_host, slave_vol, - "Config Corrupted"); - if (op_ret) { - gf_log (this1->name, GF_LOG_ERROR, - "Unable to create status file" - ". Error : %s", strerror (errno)); - ret = op_ret; - } - } +cached: + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d.inode_size", count); - GF_FREE (path_list); - GF_FREE (op_errstr); + ret = dict_set_dynstr_with_alloc (dict, key, cur_word); +out: + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, "failed to get inode size"); return ret; } -int -glusterd_volume_restart_gsyncds (glusterd_volinfo_t *volinfo) +struct mntent * +glusterd_get_mnt_entry_info (char *mnt_pt, char *buff, int buflen, + struct mntent *entry_ptr) { - GF_ASSERT (volinfo); + struct mntent *entry = NULL; + FILE *mtab = NULL; - dict_foreach (volinfo->gsync_slaves, _local_gsyncd_start, volinfo); - return 0; -} + GF_ASSERT (mnt_pt); + GF_ASSERT (buff); + GF_ASSERT (entry_ptr); -int -glusterd_restart_gsyncds (glusterd_conf_t *conf) -{ - glusterd_volinfo_t *volinfo = NULL; - int ret = 0; + mtab = setmntent (_PATH_MOUNTED, "r"); + if (!mtab) + goto out; - list_for_each_entry (volinfo, &conf->volumes, vol_list) { - glusterd_volume_restart_gsyncds (volinfo); - } - return ret; -} + entry = getmntent_r (mtab, entry_ptr, buff, buflen); -inline int -glusterd_get_dist_leaf_count (glusterd_volinfo_t *volinfo) -{ - int rcount = volinfo->replica_count; - int scount = volinfo->stripe_count; + while (1) { + if (!entry) + goto out; - if (volinfo->type == GF_CLUSTER_TYPE_DISPERSE) - return volinfo->disperse_count; + if (!strcmp (entry->mnt_dir, mnt_pt) && + strcmp (entry->mnt_type, "rootfs")) + break; + entry = getmntent_r (mtab, entry_ptr, buff, buflen); + } - return (rcount ? rcount : 1) * (scount ? scount : 1); +out: + if (NULL != mtab) { + endmntent (mtab); + } + return entry; } -int -glusterd_get_brickinfo (xlator_t *this, const char *brickname, int port, - gf_boolean_t localhost, glusterd_brickinfo_t **brickinfo) +static int +glusterd_add_brick_mount_details (glusterd_brickinfo_t *brickinfo, + dict_t *dict, int count) { - glusterd_conf_t *priv = NULL; - glusterd_volinfo_t *volinfo = NULL; - glusterd_brickinfo_t *tmpbrkinfo = NULL; - int ret = -1; + int ret = -1; + char key[1024] = {0}; + char buff [PATH_MAX] = {0}; + char base_key[1024] = {0}; + struct mntent save_entry = {0}; + char *mnt_pt = NULL; + struct mntent *entry = NULL; - GF_ASSERT (brickname); - GF_ASSERT (this); + snprintf (base_key, sizeof (base_key), "brick%d", count); - priv = this->private; - list_for_each_entry (volinfo, &priv->volumes, vol_list) { - list_for_each_entry (tmpbrkinfo, &volinfo->bricks, - brick_list) { - if (localhost && !gf_is_local_addr (tmpbrkinfo->hostname)) - continue; - if (!strcmp(tmpbrkinfo->path, brickname) && - (tmpbrkinfo->port == port)) { - *brickinfo = tmpbrkinfo; - return 0; - } - } - } - return ret; -} + ret = glusterd_get_brick_root (brickinfo->path, &mnt_pt); + if (ret) + goto out; -glusterd_brickinfo_t* -glusterd_get_brickinfo_by_position (glusterd_volinfo_t *volinfo, uint32_t pos) -{ - glusterd_brickinfo_t *tmpbrkinfo = NULL; - - list_for_each_entry (tmpbrkinfo, &volinfo->bricks, - brick_list) { - if (pos == 0) - return tmpbrkinfo; - pos--; - } - return NULL; -} - -void -glusterd_set_brick_status (glusterd_brickinfo_t *brickinfo, - gf_brick_status_t status) -{ - GF_ASSERT (brickinfo); - brickinfo->status = status; - if (GF_BRICK_STARTED == status) { - gf_log ("glusterd", GF_LOG_DEBUG, "Setting brick %s:%s status " - "to started", brickinfo->hostname, brickinfo->path); - } else { - gf_log ("glusterd", GF_LOG_DEBUG, "Setting brick %s:%s status " - "to stopped", brickinfo->hostname, brickinfo->path); - } -} - -gf_boolean_t -glusterd_is_brick_started (glusterd_brickinfo_t *brickinfo) -{ - GF_ASSERT (brickinfo); - return (brickinfo->status == GF_BRICK_STARTED); -} - -int -glusterd_friend_brick_belongs (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo, void* uuid) -{ - int ret = -1; - - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); - GF_ASSERT (uuid); - - if (uuid_is_null (brickinfo->uuid)) { - ret = glusterd_resolve_brick (brickinfo); - if (ret) { - GF_ASSERT (0); - goto out; - } + entry = glusterd_get_mnt_entry_info (mnt_pt, buff, sizeof (buff), + &save_entry); + if (!entry) { + ret = -1; + goto out; } - if (!uuid_compare (brickinfo->uuid, *((uuid_t *)uuid))) - return 0; -out: - return -1; -} - -int -glusterd_get_brick_root (char *path, char **mount_point) -{ - char *ptr = NULL; - char *mnt_pt = NULL; - struct stat brickstat = {0}; - struct stat buf = {0}; - if (!path) - goto err; - mnt_pt = gf_strdup (path); - if (!mnt_pt) - goto err; - if (stat (mnt_pt, &brickstat)) - goto err; + /* get device file */ + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.device", base_key); - while ((ptr = strrchr (mnt_pt, '/')) && - ptr != mnt_pt) { + ret = dict_set_dynstr_with_alloc (dict, key, entry->mnt_fsname); + if (ret) + goto out; - *ptr = '\0'; - if (stat (mnt_pt, &buf)) { - gf_log (THIS->name, GF_LOG_ERROR, "error in " - "stat: %s", strerror (errno)); - goto err; - } + /* fs type */ + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.fs_name", base_key); - if (brickstat.st_dev != buf.st_dev) { - *ptr = '/'; - break; - } - } + ret = dict_set_dynstr_with_alloc (dict, key, entry->mnt_type); + if (ret) + goto out; - if (ptr == mnt_pt) { - if (stat ("/", &buf)) { - gf_log (THIS->name, GF_LOG_ERROR, "error in " - "stat: %s", strerror (errno)); - goto err; - } - if (brickstat.st_dev == buf.st_dev) - strcpy (mnt_pt, "/"); - } + /* mount options */ + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.mnt_options", base_key); - *mount_point = mnt_pt; - return 0; + ret = dict_set_dynstr_with_alloc (dict, key, entry->mnt_opts); - err: + out: GF_FREE (mnt_pt); - return -1; + + return ret; } -static char* -glusterd_parse_inode_size (char *stream, char *pattern) +char* +glusterd_get_brick_mount_device (char *brick_path) { - char *needle = NULL; - char *trail = NULL; + int ret = -1; + char *mnt_pt = NULL; + char *device = NULL; + char buff [PATH_MAX] = ""; + struct mntent *entry = NULL; + struct mntent save_entry = {0,}; + xlator_t *this = NULL; - needle = strstr (stream, pattern); - if (!needle) + this = THIS; + GF_ASSERT (this); + GF_ASSERT (brick_path); + + ret = glusterd_get_brick_root (brick_path, &mnt_pt); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get mount point " + "for %s brick", brick_path); goto out; + } - needle = nwstrtail (needle, pattern); + entry = glusterd_get_mnt_entry_info (mnt_pt, buff, sizeof (buff), + &save_entry); + if (NULL == entry) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get mnt entry " + "for %s mount path", mnt_pt); + goto out; + } - trail = needle; - while (trail && isdigit (*trail)) trail++; - if (trail) - *trail = '\0'; + /* get the fs_name/device */ + device = gf_strdup (entry->mnt_fsname); out: - return needle; + return device; } -static struct fs_info { - char *fs_type_name; - char *fs_tool_name; - char *fs_tool_arg; - char *fs_tool_pattern; - char *fs_tool_pkg; -} glusterd_fs[] = { - /* some linux have these in /usr/sbin/and others in /sbin/? */ - { "xfs", "xfs_info", NULL, "isize=", "xfsprogs" }, - { "ext3", "tune2fs", "-l", "Inode size:", "e2fsprogs" }, - { "ext4", "tune2fs", "-l", "Inode size:", "e2fsprogs" }, - { "btrfs", NULL, NULL, NULL, NULL }, - { NULL, NULL, NULL, NULL, NULL} -}; - -static int -glusterd_add_inode_size_to_dict (dict_t *dict, int count) +int +glusterd_add_brick_detail_to_dict (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + dict_t *dict, int count) { int ret = -1; + uint64_t memtotal = 0; + uint64_t memfree = 0; + uint64_t inodes_total = 0; + uint64_t inodes_free = 0; + uint64_t block_size = 0; char key[1024] = {0}; - char buffer[4096] = {0}; - char *inode_size = NULL; - char *device = NULL; - char *fs_name = NULL; - char *cur_word = NULL; - char *trail = NULL; - runner_t runner = {0, }; - struct fs_info *fs = NULL; - char fs_tool_name[256] = {0, }; - static dict_t *cached_fs = NULL; + char base_key[1024] = {0}; + struct statvfs brickstat = {0}; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + GF_ASSERT (dict); + + snprintf (base_key, sizeof (base_key), "brick%d", count); + + ret = statvfs (brickinfo->path, &brickstat); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "statfs error: %s ", + strerror (errno)); + goto out; + } + /* file system block size */ + block_size = brickstat.f_bsize; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d.device", count); - ret = dict_get_str (dict, key, &device); + snprintf (key, sizeof (key), "%s.block_size", base_key); + ret = dict_set_uint64 (dict, key, block_size); if (ret) goto out; - if (cached_fs) { - if (dict_get_str (cached_fs, device, &cur_word) == 0) { - goto cached; - } - } else { - cached_fs = dict_new (); - } + /* free space in brick */ + memfree = brickstat.f_bfree * brickstat.f_bsize; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.free", base_key); + ret = dict_set_uint64 (dict, key, memfree); + if (ret) + goto out; + /* total space of brick */ + memtotal = brickstat.f_blocks * brickstat.f_bsize; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d.fs_name", count); - ret = dict_get_str (dict, key, &fs_name); + snprintf (key, sizeof (key), "%s.total", base_key); + ret = dict_set_uint64 (dict, key, memtotal); if (ret) goto out; - runinit (&runner); - runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); + /* inodes: total and free counts only for ext2/3/4 and xfs */ + inodes_total = brickstat.f_files; + if (inodes_total) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.total_inodes", base_key); + ret = dict_set_uint64 (dict, key, inodes_total); + if (ret) + goto out; + } - for (fs = glusterd_fs ; fs->fs_type_name; fs++) { - if (strcmp (fs_name, fs->fs_type_name) == 0) { - snprintf (fs_tool_name, sizeof (fs_tool_name), - "/usr/sbin/%s", fs->fs_tool_name); - if (access (fs_tool_name, R_OK|X_OK) == 0) - runner_add_arg (&runner, fs_tool_name); - else { - snprintf (fs_tool_name, sizeof (fs_tool_name), - "/sbin/%s", fs->fs_tool_name); - if (access (fs_tool_name, R_OK|X_OK) == 0) - runner_add_arg (&runner, fs_tool_name); - } - break; - } - } - - if (runner.argv[0]) { - if (fs->fs_tool_arg) - runner_add_arg (&runner, fs->fs_tool_arg); - runner_add_arg (&runner, device); - } else { - gf_log (THIS->name, GF_LOG_ERROR, "could not find %s to get" - "inode size for %s (%s): %s package missing?", - fs->fs_tool_name, device, fs_name, fs->fs_tool_pkg); - goto out; - } - - ret = runner_start (&runner); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "failed to execute " - "\"%s\": %s", fs->fs_tool_name, strerror (errno)); - /* - * Runner_start might return an error after the child has - * been forked, e.g. if the program isn't there. In that - * case, we still need to call runner_end to reap the - * child and free resources. Fortunately, that seems to - * be harmless for other kinds of failures. - */ - (void) runner_end (&runner); - goto out; - } - - for (;;) { - if (fgets (buffer, sizeof (buffer), - runner_chio (&runner, STDOUT_FILENO)) == NULL) - break; - trail = strrchr (buffer, '\n'); - if (trail) - *trail = '\0'; - - cur_word = - glusterd_parse_inode_size (buffer, fs->fs_tool_pattern); - - if (cur_word) - break; + inodes_free = brickstat.f_ffree; + if (inodes_free) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.free_inodes", base_key); + ret = dict_set_uint64 (dict, key, inodes_free); + if (ret) + goto out; } - ret = runner_end (&runner); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, - "%s exited with non-zero exit status", - fs->fs_tool_name); - - goto out; - } - if (!cur_word) { - ret = -1; - gf_log (THIS->name, GF_LOG_ERROR, - "Unable to retrieve inode size using %s", - fs->fs_tool_name); + ret = glusterd_add_brick_mount_details (brickinfo, dict, count); + if (ret) goto out; - } - - if (dict_set_dynstr_with_alloc (cached_fs, device, cur_word)) { - /* not fatal if not entered into the cache */ - gf_log (THIS->name, GF_LOG_DEBUG, - "failed to cache fs inode size for %s", device); - } - -cached: - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d.inode_size", count); - - ret = dict_set_dynstr_with_alloc (dict, key, cur_word); -out: + ret = glusterd_add_inode_size_to_dict (dict, count); + out: if (ret) - gf_log (THIS->name, GF_LOG_ERROR, "failed to get inode size"); + gf_log (this->name, GF_LOG_DEBUG, "Error adding brick" + " detail to dict: %s", strerror (errno)); return ret; } -struct mntent * -glusterd_get_mnt_entry_info (char *mnt_pt, char *buff, int buflen, - struct mntent *entry_ptr) +int32_t +glusterd_add_brick_to_dict (glusterd_volinfo_t *volinfo, + glusterd_brickinfo_t *brickinfo, + dict_t *dict, int32_t count) { - struct mntent *entry = NULL; - FILE *mtab = NULL; - - GF_ASSERT (mnt_pt); - GF_ASSERT (buff); - GF_ASSERT (entry_ptr); - - mtab = setmntent (_PATH_MOUNTED, "r"); - if (!mtab) - goto out; - - entry = getmntent_r (mtab, entry_ptr, buff, buflen); - while (1) { - if (!entry) - goto out; + int ret = -1; + int32_t pid = -1; + int32_t brick_online = -1; + char key[1024] = {0}; + char base_key[1024] = {0}; + char pidfile[PATH_MAX] = {0}; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; - if (!strcmp (entry->mnt_dir, mnt_pt) && - strcmp (entry->mnt_type, "rootfs")) - break; - entry = getmntent_r (mtab, entry_ptr, buff, buflen); - } + GF_ASSERT (volinfo); + GF_ASSERT (brickinfo); + GF_ASSERT (dict); -out: - if (NULL != mtab) { - endmntent (mtab); - } - return entry; -} + this = THIS; + GF_ASSERT (this); -static int -glusterd_add_brick_mount_details (glusterd_brickinfo_t *brickinfo, - dict_t *dict, int count) -{ - int ret = -1; - char key[1024] = {0}; - char buff [PATH_MAX] = {0}; - char base_key[1024] = {0}; - struct mntent save_entry = {0}; - char *mnt_pt = NULL; - struct mntent *entry = NULL; + priv = this->private; snprintf (base_key, sizeof (base_key), "brick%d", count); + snprintf (key, sizeof (key), "%s.hostname", base_key); - ret = glusterd_get_brick_root (brickinfo->path, &mnt_pt); + ret = dict_set_str (dict, key, brickinfo->hostname); if (ret) goto out; - entry = glusterd_get_mnt_entry_info (mnt_pt, buff, sizeof (buff), - &save_entry); - if (!entry) { - ret = -1; + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.path", base_key); + ret = dict_set_str (dict, key, brickinfo->path); + if (ret) goto out; - } - /* get device file */ + /* add peer uuid */ memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.device", base_key); + snprintf (key, sizeof (key), "%s.peerid", base_key); + ret = dict_set_dynstr_with_alloc (dict, key, + uuid_utoa (brickinfo->uuid)); + if (ret) { + goto out; + } - ret = dict_set_dynstr_with_alloc (dict, key, entry->mnt_fsname); + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.port", base_key); + ret = dict_set_int32 (dict, key, brickinfo->port); if (ret) goto out; - /* fs type */ - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.fs_name", base_key); + GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, brickinfo, priv); - ret = dict_set_dynstr_with_alloc (dict, key, entry->mnt_type); + brick_online = gf_is_service_running (pidfile, &pid); + + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "%s.pid", base_key); + ret = dict_set_int32 (dict, key, pid); if (ret) goto out; - /* mount options */ memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.mnt_options", base_key); - - ret = dict_set_dynstr_with_alloc (dict, key, entry->mnt_opts); + snprintf (key, sizeof (key), "%s.status", base_key); + ret = dict_set_int32 (dict, key, brick_online); - out: - GF_FREE (mnt_pt); +out: + if (ret) + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } -char* -glusterd_get_brick_mount_device (char *brick_path) +int32_t +glusterd_get_all_volnames (dict_t *dict) { - int ret = -1; - char *mnt_pt = NULL; - char *device = NULL; - char buff [PATH_MAX] = ""; - struct mntent *entry = NULL; - struct mntent save_entry = {0,}; - xlator_t *this = NULL; + int ret = -1; + int32_t vol_count = 0; + char key[256] = {0}; + glusterd_volinfo_t *entry = NULL; + glusterd_conf_t *priv = NULL; - this = THIS; - GF_ASSERT (this); - GF_ASSERT (brick_path); + priv = THIS->private; + GF_ASSERT (priv); - ret = glusterd_get_brick_root (brick_path, &mnt_pt); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get mount point " - "for %s brick", brick_path); - goto out; - } + list_for_each_entry (entry, &priv->volumes, vol_list) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "vol%d", vol_count); + ret = dict_set_str (dict, key, entry->volname); + if (ret) + goto out; - entry = glusterd_get_mnt_entry_info (mnt_pt, buff, sizeof (buff), - &save_entry); - if (NULL == entry) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get mnt entry " - "for %s mount path", mnt_pt); - goto out; + vol_count++; } - /* get the fs_name/device */ - device = gf_strdup (entry->mnt_fsname); + ret = dict_set_int32 (dict, "vol_count", vol_count); -out: - return device; + out: + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, "failed to get all " + "volume names for status"); + return ret; } int -glusterd_add_brick_detail_to_dict (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo, - dict_t *dict, int count) -{ - int ret = -1; - uint64_t memtotal = 0; - uint64_t memfree = 0; - uint64_t inodes_total = 0; - uint64_t inodes_free = 0; - uint64_t block_size = 0; - char key[1024] = {0}; - char base_key[1024] = {0}; - struct statvfs brickstat = {0}; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); - GF_ASSERT (dict); - - snprintf (base_key, sizeof (base_key), "brick%d", count); - - ret = statvfs (brickinfo->path, &brickstat); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "statfs error: %s ", - strerror (errno)); - goto out; - } - - /* file system block size */ - block_size = brickstat.f_bsize; - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.block_size", base_key); - ret = dict_set_uint64 (dict, key, block_size); - if (ret) - goto out; - - /* free space in brick */ - memfree = brickstat.f_bfree * brickstat.f_bsize; - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.free", base_key); - ret = dict_set_uint64 (dict, key, memfree); - if (ret) - goto out; - - /* total space of brick */ - memtotal = brickstat.f_blocks * brickstat.f_bsize; - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.total", base_key); - ret = dict_set_uint64 (dict, key, memtotal); - if (ret) - goto out; - - /* inodes: total and free counts only for ext2/3/4 and xfs */ - inodes_total = brickstat.f_files; - if (inodes_total) { - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.total_inodes", base_key); - ret = dict_set_uint64 (dict, key, inodes_total); - if (ret) - goto out; - } - - inodes_free = brickstat.f_ffree; - if (inodes_free) { - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.free_inodes", base_key); - ret = dict_set_uint64 (dict, key, inodes_free); - if (ret) - goto out; - } - - ret = glusterd_add_brick_mount_details (brickinfo, dict, count); - if (ret) - goto out; - - ret = glusterd_add_inode_size_to_dict (dict, count); - out: - if (ret) - gf_log (this->name, GF_LOG_DEBUG, "Error adding brick" - " detail to dict: %s", strerror (errno)); - return ret; -} - -int32_t -glusterd_add_brick_to_dict (glusterd_volinfo_t *volinfo, - glusterd_brickinfo_t *brickinfo, - dict_t *dict, int32_t count) -{ - - int ret = -1; - int32_t pid = -1; - int32_t brick_online = -1; - char key[1024] = {0}; - char base_key[1024] = {0}; - char pidfile[PATH_MAX] = {0}; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - - GF_ASSERT (volinfo); - GF_ASSERT (brickinfo); - GF_ASSERT (dict); - - this = THIS; - GF_ASSERT (this); - - priv = this->private; - - snprintf (base_key, sizeof (base_key), "brick%d", count); - snprintf (key, sizeof (key), "%s.hostname", base_key); - - ret = dict_set_str (dict, key, brickinfo->hostname); - if (ret) - goto out; - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.path", base_key); - ret = dict_set_str (dict, key, brickinfo->path); - if (ret) - goto out; - - /* add peer uuid */ - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.peerid", base_key); - ret = dict_set_dynstr_with_alloc (dict, key, - uuid_utoa (brickinfo->uuid)); - if (ret) { - goto out; - } - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.port", base_key); - ret = dict_set_int32 (dict, key, brickinfo->port); - if (ret) - goto out; - - GLUSTERD_GET_BRICK_PIDFILE (pidfile, volinfo, brickinfo, priv); - - brick_online = gf_is_service_running (pidfile, &pid); - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.pid", base_key); - ret = dict_set_int32 (dict, key, pid); - if (ret) - goto out; - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.status", base_key); - ret = dict_set_int32 (dict, key, brick_online); - -out: - if (ret) - gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -glusterd_add_snapd_to_dict (glusterd_volinfo_t *volinfo, - dict_t *dict, int32_t count) -{ - - int ret = -1; - int32_t pid = -1; - int32_t brick_online = -1; - char key[1024] = {0}; - char base_key[1024] = {0}; - char pidfile[PATH_MAX] = {0}; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - - - GF_ASSERT (volinfo); - GF_ASSERT (dict); - - this = THIS; - GF_ASSERT (this); - - priv = this->private; - - snprintf (base_key, sizeof (base_key), "brick%d", count); - snprintf (key, sizeof (key), "%s.hostname", base_key); - ret = dict_set_str (dict, key, "Snapshot Daemon"); - if (ret) - goto out; - - snprintf (key, sizeof (key), "%s.path", base_key); - ret = dict_set_dynstr (dict, key, gf_strdup (uuid_utoa (MY_UUID))); - if (ret) - goto out; - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.port", base_key); - ret = dict_set_int32 (dict, key, volinfo->snapd.port); - if (ret) - goto out; - - glusterd_get_snapd_pidfile (volinfo, pidfile, sizeof (pidfile)); - - brick_online = gf_is_service_running (pidfile, &pid); - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.pid", base_key); - ret = dict_set_int32 (dict, key, pid); - if (ret) - goto out; - - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "%s.status", base_key); - ret = dict_set_int32 (dict, key, brick_online); - -out: - if (ret) - gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); - - return ret; -} - -int32_t -glusterd_get_all_volnames (dict_t *dict) -{ - int ret = -1; - int32_t vol_count = 0; - char key[256] = {0}; - glusterd_volinfo_t *entry = NULL; - glusterd_conf_t *priv = NULL; - - priv = THIS->private; - GF_ASSERT (priv); - - list_for_each_entry (entry, &priv->volumes, vol_list) { - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "vol%d", vol_count); - ret = dict_set_str (dict, key, entry->volname); - if (ret) - goto out; - - vol_count++; - } - - ret = dict_set_int32 (dict, "vol_count", vol_count); - - out: - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, "failed to get all " - "volume names for status"); - return ret; -} - -int -glusterd_all_volume_cond_check (glusterd_condition_func func, int status, - void *ctx) +glusterd_all_volume_cond_check (glusterd_condition_func func, int status, + void *ctx) { glusterd_conf_t *priv = NULL; glusterd_volinfo_t *volinfo = NULL; @@ -10336,3353 +8610,1438 @@ glusterd_volume_rebalance_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict) if (!ret) { memset (key, 0, 256); snprintf (key, 256, "lookups-%d", current_index); - ret = dict_set_uint64 (ctx_dict, key, value); - if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, - "failed to set lookuped file count"); - } - } - - memset (key, 0, 256); - snprintf (key, 256, "status-%d", index); - ret = dict_get_int32 (rsp_dict, key, &value32); - if (!ret) { - memset (key, 0, 256); - snprintf (key, 256, "status-%d", current_index); - ret = dict_set_int32 (ctx_dict, key, value32); - if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, - "failed to set status"); - } - } - - memset (key, 0, 256); - snprintf (key, 256, "failures-%d", index); - ret = dict_get_uint64 (rsp_dict, key, &value); - if (!ret) { - memset (key, 0, 256); - snprintf (key, 256, "failures-%d", current_index); - ret = dict_set_uint64 (ctx_dict, key, value); - if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, - "failed to set failure count"); - } - } - - memset (key, 0, 256); - snprintf (key, 256, "skipped-%d", index); - ret = dict_get_uint64 (rsp_dict, key, &value); - if (!ret) { - memset (key, 0, 256); - snprintf (key, 256, "skipped-%d", current_index); - ret = dict_set_uint64 (ctx_dict, key, value); - if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, - "failed to set skipped count"); - } - } - memset (key, 0, 256); - snprintf (key, 256, "run-time-%d", index); - ret = dict_get_double (rsp_dict, key, &elapsed_time); - if (!ret) { - memset (key, 0, 256); - snprintf (key, 256, "run-time-%d", current_index); - ret = dict_set_double (ctx_dict, key, elapsed_time); - if (ret) { - gf_log (THIS->name, GF_LOG_DEBUG, - "failed to set run-time"); - } - } - - ret = 0; - -out: - return ret; -} - -int -glusterd_snap_config_use_rsp_dict (dict_t *dst, dict_t *src) -{ - char buf[PATH_MAX] = ""; - char *volname = NULL; - int ret = -1; - int config_command = 0; - uint64_t i = 0; - uint64_t hard_limit = GLUSTERD_SNAPS_MAX_HARD_LIMIT; - uint64_t soft_limit = GLUSTERD_SNAPS_DEF_SOFT_LIMIT_PERCENT; - uint64_t value = 0; - uint64_t voldisplaycount = 0; - - if (!dst || !src) { - gf_log ("", GF_LOG_ERROR, "Source or Destination " - "dict is empty."); - goto out; - } - - ret = dict_get_int32 (dst, "config-command", &config_command); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "failed to get config-command type"); - goto out; - } - - switch (config_command) { - case GF_SNAP_CONFIG_DISPLAY: - ret = dict_get_uint64 (src, - GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, - &hard_limit); - if (!ret) { - ret = dict_set_uint64 (dst, - GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, - hard_limit); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to set snap_max_hard_limit"); - goto out; - } - } else { - /* Received dummy response from other nodes */ - ret = 0; - goto out; - } - - ret = dict_get_uint64 (src, - GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT, - &soft_limit); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to get snap_max_soft_limit"); - goto out; - } - - ret = dict_set_uint64 (dst, - GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT, - soft_limit); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to set snap_max_soft_limit"); - goto out; - } - - ret = dict_get_uint64 (src, "voldisplaycount", - &voldisplaycount); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to get voldisplaycount"); - goto out; - } - - ret = dict_set_uint64 (dst, "voldisplaycount", - voldisplaycount); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to set voldisplaycount"); - goto out; - } - - for (i = 0; i < voldisplaycount; i++) { - snprintf (buf, sizeof(buf), "volume%"PRIu64"-volname", i); - ret = dict_get_str (src, buf, &volname); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to get %s", buf); - goto out; - } - ret = dict_set_str (dst, buf, volname); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to set %s", buf); - goto out; - } - - snprintf (buf, sizeof(buf), - "volume%"PRIu64"-snap-max-hard-limit", i); - ret = dict_get_uint64 (src, buf, &value); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to get %s", buf); - goto out; - } - ret = dict_set_uint64 (dst, buf, value); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to set %s", buf); - goto out; - } - - snprintf (buf, sizeof(buf), - "volume%"PRIu64"-active-hard-limit", i); - ret = dict_get_uint64 (src, buf, &value); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to get %s", buf); - goto out; - } - ret = dict_set_uint64 (dst, buf, value); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to set %s", buf); - goto out; - } - - snprintf (buf, sizeof(buf), - "volume%"PRIu64"-snap-max-soft-limit", i); - ret = dict_get_uint64 (src, buf, &value); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to get %s", buf); - goto out; - } - ret = dict_set_uint64 (dst, buf, value); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Unable to set %s", buf); - goto out; - } - } - - break; - default: - break; - } - - ret = 0; -out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - -int -glusterd_merge_brick_status (dict_t *dst, dict_t *src) -{ - int64_t volume_count = 0; - int64_t index = 0; - int64_t j = 0; - int64_t brick_count = 0; - int64_t brick_order = 0; - char key[PATH_MAX] = {0, }; - char snapbrckcnt[PATH_MAX] = {0, }; - char snapbrckord[PATH_MAX] = {0, }; - int ret = -1; - int32_t brick_online = 0; - xlator_t *this = NULL; - int32_t snap_command = 0; - - this = THIS; - GF_ASSERT (this); - - if (!dst || !src) { - gf_log (this->name, GF_LOG_ERROR, "Source or Destination " - "dict is empty."); - goto out; - } - - ret = dict_get_int32 (dst, "type", &snap_command); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " - "the snapshot command"); - goto out; - } - - if (snap_command == GF_SNAP_OPTION_TYPE_DELETE) { - gf_log (this->name, GF_LOG_DEBUG, "snapshot delete command." - " Need not merge the status of the bricks"); - ret = 0; - goto out; - } - - ret = dict_get_int64 (src, "volcount", &volume_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get the volume count"); - goto out; - } - - for (index = 0; index < volume_count; index++) { - ret = snprintf (snapbrckcnt, sizeof(snapbrckcnt) - 1, - "snap-vol%"PRId64"_brickcount", index+1); - ret = dict_get_int64 (src, snapbrckcnt, &brick_count); - if (ret) { - gf_log (this->name, GF_LOG_TRACE, - "No bricks for this volume in this dict (%s)", - snapbrckcnt); - continue; - } - - for (j = 0; j < brick_count; j++) { - /* Fetching data from source dict */ - snprintf (snapbrckord, sizeof(snapbrckord) - 1, - "snap-vol%"PRId64".brick%"PRId64".order", index+1, j); - - ret = dict_get_int64 (src, snapbrckord, &brick_order); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to get brick order (%s)", - snapbrckord); - goto out; - } - - snprintf (key, sizeof (key) - 1, - "snap-vol%"PRId64".brick%"PRId64".status", index+1, - brick_order); - ret = dict_get_int32 (src, key, &brick_online); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get the brick status (%s)", key); - goto out; - } - - ret = dict_set_int32 (dst, key, brick_online); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "set the brick status (%s)", key); - goto out; - } - brick_online = 0; - } - } - - ret = 0; - -out: - return ret; -} - -/* Aggregate missed_snap_counts from different nodes and save it * - * in the req_dict of the originator node */ -int -glusterd_snap_create_use_rsp_dict (dict_t *dst, dict_t *src) -{ - char *buf = NULL; - char *tmp_str = NULL; - char name_buf[PATH_MAX] = ""; - int32_t i = -1; - int32_t ret = -1; - int32_t src_missed_snap_count = -1; - int32_t dst_missed_snap_count = -1; - xlator_t *this = NULL; - int8_t soft_limit_flag = -1; - - this = THIS; - GF_ASSERT (this); - - if (!dst || !src) { - gf_log (this->name, GF_LOG_ERROR, "Source or Destination " - "dict is empty."); - goto out; - } - - ret = glusterd_merge_brick_status (dst, src); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to merge brick " - "status"); - goto out; - } - - ret = dict_get_str (src, "snapuuid", &buf); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to get snap UUID"); - goto out; - } - - ret = dict_set_dynstr_with_alloc (dst, "snapuuid", buf); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to set snap uuid in dict"); - goto out; - } - - /* set in dst dictionary soft-limit-reach only if soft-limit-reach - * is present src dictionary */ - ret = dict_get_int8 (src, "soft-limit-reach", &soft_limit_flag); - if (!ret) { - ret = dict_set_int8 (dst, "soft-limit-reach", soft_limit_flag); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set " - "soft_limit_flag"); - goto out; - } - } - - ret = dict_get_int32 (src, "missed_snap_count", - &src_missed_snap_count); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, "No missed snaps"); - ret = 0; - goto out; - } - - ret = dict_get_int32 (dst, "missed_snap_count", - &dst_missed_snap_count); - if (ret) { - /* Initialize dst_missed_count for the first time */ - dst_missed_snap_count = 0; - } - - for (i = 0; i < src_missed_snap_count; i++) { - snprintf (name_buf, sizeof(name_buf), "missed_snaps_%d", - i); - ret = dict_get_str (src, name_buf, &buf); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to fetch %s", name_buf); - goto out; - } - - snprintf (name_buf, sizeof(name_buf), "missed_snaps_%d", - dst_missed_snap_count); - - tmp_str = gf_strdup (buf); - if (!tmp_str) { - ret = -1; - goto out; - } - - ret = dict_set_dynstr (dst, name_buf, tmp_str); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set %s", name_buf); - goto out; - } - - tmp_str = NULL; - dst_missed_snap_count++; - } - - ret = dict_set_int32 (dst, "missed_snap_count", dst_missed_snap_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Unable to set dst_missed_snap_count"); - goto out; - } - -out: - if (ret && tmp_str) - GF_FREE(tmp_str); - - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -int -glusterd_snap_use_rsp_dict (dict_t *dst, dict_t *src) -{ - int ret = -1; - int32_t snap_command = 0; - - if (!dst || !src) { - gf_log ("", GF_LOG_ERROR, "Source or Destination " - "dict is empty."); - goto out; - } - - ret = dict_get_int32 (dst, "type", &snap_command); - if (ret) { - gf_log ("", GF_LOG_ERROR, "unable to get the type of " - "the snapshot command"); - goto out; - } - - switch (snap_command) { - case GF_SNAP_OPTION_TYPE_CREATE: - case GF_SNAP_OPTION_TYPE_DELETE: - ret = glusterd_snap_create_use_rsp_dict (dst, src); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to use rsp dict"); - goto out; - } - break; - case GF_SNAP_OPTION_TYPE_CONFIG: - ret = glusterd_snap_config_use_rsp_dict (dst, src); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to use rsp dict"); - goto out; - } - break; - default: - // copy the response dictinary's contents to the dict to be - // sent back to the cli - dict_copy (src, dst); - break; - } - - ret = 0; -out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - -int -glusterd_sys_exec_output_rsp_dict (dict_t *dst, dict_t *src) -{ - char output_name[PATH_MAX] = ""; - char *output = NULL; - int ret = 0; - int i = 0; - int len = 0; - int src_output_count = 0; - int dst_output_count = 0; - - if (!dst || !src) { - gf_log ("", GF_LOG_ERROR, "Source or Destination " - "dict is empty."); - goto out; - } - - ret = dict_get_int32 (dst, "output_count", &dst_output_count); - - ret = dict_get_int32 (src, "output_count", &src_output_count); - if (ret) { - gf_log ("", GF_LOG_DEBUG, "No output from source"); - ret = 0; - goto out; - } - - for (i = 1; i <= src_output_count; i++) { - len = snprintf (output_name, sizeof(output_name) - 1, - "output_%d", i); - output_name[len] = '\0'; - ret = dict_get_str (src, output_name, &output); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to fetch %s", - output_name); - goto out; - } - - len = snprintf (output_name, sizeof(output_name) - 1, - "output_%d", i+dst_output_count); - output_name[len] = '\0'; - ret = dict_set_dynstr (dst, output_name, gf_strdup (output)); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to set %s", - output_name); - goto out; - } - } - - ret = dict_set_int32 (dst, "output_count", - dst_output_count+src_output_count); -out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - -int -glusterd_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict) -{ - int ret = 0; - glusterd_op_t op = GD_OP_NONE; - - op = glusterd_op_get_op (); - GF_ASSERT (aggr); - GF_ASSERT (rsp_dict); - - if (!aggr) - goto out; - dict_copy (rsp_dict, aggr); -out: - return ret; -} - -int -glusterd_volume_heal_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict) -{ - int ret = 0; - dict_t *ctx_dict = NULL; - glusterd_op_t op = GD_OP_NONE; - - GF_ASSERT (rsp_dict); - - op = glusterd_op_get_op (); - GF_ASSERT (GD_OP_HEAL_VOLUME == op); - - if (aggr) { - ctx_dict = aggr; - - } else { - ctx_dict = glusterd_op_get_ctx (op); - } - - if (!ctx_dict) - goto out; - dict_copy (rsp_dict, ctx_dict); -out: - return ret; -} - -int -_profile_volume_add_brick_rsp (dict_t *this, char *key, data_t *value, - void *data) -{ - char new_key[256] = {0}; - glusterd_pr_brick_rsp_conv_t *rsp_ctx = NULL; - data_t *new_value = NULL; - - rsp_ctx = data; - new_value = data_copy (value); - GF_ASSERT (new_value); - snprintf (new_key, sizeof (new_key), "%d-%s", rsp_ctx->count, key); - dict_set (rsp_ctx->dict, new_key, new_value); - return 0; -} - -int -glusterd_volume_quota_copy_to_op_ctx_dict (dict_t *dict, dict_t *rsp_dict) -{ - int ret = -1; - int i = 0; - int count = 0; - int rsp_dict_count = 0; - char *uuid_str = NULL; - char *uuid_str_dup = NULL; - char key[256] = {0,}; - xlator_t *this = NULL; - int type = GF_QUOTA_OPTION_TYPE_NONE; - - this = THIS; - GF_ASSERT (this); - - ret = dict_get_int32 (dict, "type", &type); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get quota opcode"); - goto out; - } - - if ((type != GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) && - (type != GF_QUOTA_OPTION_TYPE_REMOVE)) { - dict_copy (rsp_dict, dict); - ret = 0; - goto out; - } - - ret = dict_get_int32 (rsp_dict, "count", &rsp_dict_count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get the count of " - "gfids from the rsp dict"); - goto out; - } - - ret = dict_get_int32 (dict, "count", &count); - if (ret) - /* The key "count" is absent in op_ctx when this function is - * called after self-staging on the originator. This must not - * be treated as error. - */ - gf_log (this->name, GF_LOG_DEBUG, "Failed to get count of gfids" - " from req dict. This could be because count is not yet" - " copied from rsp_dict into op_ctx"); - - for (i = 0; i < rsp_dict_count; i++) { - snprintf (key, sizeof(key)-1, "gfid%d", i); - - ret = dict_get_str (rsp_dict, key, &uuid_str); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get gfid " - "from rsp dict"); - goto out; - } - - snprintf (key, sizeof (key)-1, "gfid%d", i + count); - - uuid_str_dup = gf_strdup (uuid_str); - if (!uuid_str_dup) { - ret = -1; - goto out; - } - - ret = dict_set_dynstr (dict, key, uuid_str_dup); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set gfid " - "from rsp dict into req dict"); - GF_FREE (uuid_str_dup); - goto out; - } - } - - ret = dict_set_int32 (dict, "count", rsp_dict_count + count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set aggregated " - "count in req dict"); - goto out; - } - -out: - return ret; -} - -int -glusterd_profile_volume_brick_rsp (void *pending_entry, - dict_t *rsp_dict, dict_t *op_ctx, - char **op_errstr, gd_node_type type) -{ - int ret = 0; - glusterd_pr_brick_rsp_conv_t rsp_ctx = {0}; - int32_t count = 0; - char brick[PATH_MAX+1024] = {0}; - char key[256] = {0}; - char *full_brick = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - - GF_ASSERT (rsp_dict); - GF_ASSERT (op_ctx); - GF_ASSERT (op_errstr); - GF_ASSERT (pending_entry); - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - - ret = dict_get_int32 (op_ctx, "count", &count); - if (ret) { - count = 1; - } else { - count++; - } - snprintf (key, sizeof (key), "%d-brick", count); - if (type == GD_NODE_BRICK) { - brickinfo = pending_entry; - snprintf (brick, sizeof (brick), "%s:%s", brickinfo->hostname, - brickinfo->path); - } else if (type == GD_NODE_NFS) { - snprintf (brick, sizeof (brick), "%s", uuid_utoa (MY_UUID)); - } - full_brick = gf_strdup (brick); - GF_ASSERT (full_brick); - ret = dict_set_dynstr (op_ctx, key, full_brick); - - rsp_ctx.count = count; - rsp_ctx.dict = op_ctx; - dict_foreach (rsp_dict, _profile_volume_add_brick_rsp, &rsp_ctx); - dict_del (op_ctx, "count"); - ret = dict_set_int32 (op_ctx, "count", count); - return ret; -} - -//input-key: :-* -//output-key: -* -int -_heal_volume_add_shd_rsp (dict_t *this, char *key, data_t *value, void *data) -{ - char new_key[256] = {0,}; - char int_str[16] = {0}; - data_t *new_value = NULL; - char *rxl_end = NULL; - char *rxl_child_end = NULL; - glusterd_volinfo_t *volinfo = NULL; - int rxl_id = 0; - int rxl_child_id = 0; - int brick_id = 0; - int int_len = 0; - int ret = 0; - glusterd_heal_rsp_conv_t *rsp_ctx = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - - rsp_ctx = data; - rxl_end = strchr (key, '-'); - if (!rxl_end) - goto out; - - int_len = strlen (key) - strlen (rxl_end); - strncpy (int_str, key, int_len); - int_str[int_len] = '\0'; - ret = gf_string2int (int_str, &rxl_id); - if (ret) - goto out; - - rxl_child_end = strchr (rxl_end + 1, '-'); - if (!rxl_child_end) - goto out; - - int_len = strlen (rxl_end) - strlen (rxl_child_end) - 1; - strncpy (int_str, rxl_end + 1, int_len); - int_str[int_len] = '\0'; - ret = gf_string2int (int_str, &rxl_child_id); - if (ret) - goto out; - - volinfo = rsp_ctx->volinfo; - brick_id = rxl_id * volinfo->replica_count + rxl_child_id; - - if (!strcmp (rxl_child_end, "-status")) { - brickinfo = glusterd_get_brickinfo_by_position (volinfo, - brick_id); - if (!brickinfo) - goto out; - if (!glusterd_is_local_brick (rsp_ctx->this, volinfo, - brickinfo)) - goto out; - } - new_value = data_copy (value); - snprintf (new_key, sizeof (new_key), "%d%s", brick_id, rxl_child_end); - dict_set (rsp_ctx->dict, new_key, new_value); - -out: - return 0; -} - -int -_heal_volume_add_shd_rsp_of_statistics (dict_t *this, char *key, data_t - *value, void *data) -{ - char new_key[256] = {0,}; - char int_str[16] = {0,}; - char key_begin_string[128] = {0,}; - data_t *new_value = NULL; - char *rxl_end = NULL; - char *rxl_child_end = NULL; - glusterd_volinfo_t *volinfo = NULL; - char *key_begin_str = NULL; - int rxl_id = 0; - int rxl_child_id = 0; - int brick_id = 0; - int int_len = 0; - int ret = 0; - glusterd_heal_rsp_conv_t *rsp_ctx = NULL; - glusterd_brickinfo_t *brickinfo = NULL; - - rsp_ctx = data; - key_begin_str = strchr (key, '-'); - if (!key_begin_str) - goto out; - - int_len = strlen (key) - strlen (key_begin_str); - strncpy (key_begin_string, key, int_len); - key_begin_string[int_len] = '\0'; - - rxl_end = strchr (key_begin_str + 1, '-'); - if (!rxl_end) - goto out; - - int_len = strlen (key_begin_str) - strlen (rxl_end) - 1; - strncpy (int_str, key_begin_str + 1, int_len); - int_str[int_len] = '\0'; - ret = gf_string2int (int_str, &rxl_id); - if (ret) - goto out; - - - rxl_child_end = strchr (rxl_end + 1, '-'); - if (!rxl_child_end) - goto out; - - int_len = strlen (rxl_end) - strlen (rxl_child_end) - 1; - strncpy (int_str, rxl_end + 1, int_len); - int_str[int_len] = '\0'; - ret = gf_string2int (int_str, &rxl_child_id); - if (ret) - goto out; - - volinfo = rsp_ctx->volinfo; - brick_id = rxl_id * volinfo->replica_count + rxl_child_id; - - brickinfo = glusterd_get_brickinfo_by_position (volinfo, brick_id); - if (!brickinfo) - goto out; - if (!glusterd_is_local_brick (rsp_ctx->this, volinfo, brickinfo)) - goto out; - - new_value = data_copy (value); - snprintf (new_key, sizeof (new_key), "%s-%d%s", key_begin_string, - brick_id, rxl_child_end); - dict_set (rsp_ctx->dict, new_key, new_value); - -out: - return 0; - -} - -int -glusterd_heal_volume_brick_rsp (dict_t *req_dict, dict_t *rsp_dict, - dict_t *op_ctx, char **op_errstr) -{ - int ret = 0; - glusterd_heal_rsp_conv_t rsp_ctx = {0}; - char *volname = NULL; - glusterd_volinfo_t *volinfo = NULL; - int heal_op = -1; - - GF_ASSERT (rsp_dict); - GF_ASSERT (op_ctx); - GF_ASSERT (op_errstr); - - ret = dict_get_str (req_dict, "volname", &volname); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); - goto out; - } - - ret = dict_get_int32 (req_dict, "heal-op", &heal_op); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get heal_op"); - goto out; - } - - - ret = glusterd_volinfo_find (volname, &volinfo); - - if (ret) - goto out; - - rsp_ctx.dict = op_ctx; - rsp_ctx.volinfo = volinfo; - rsp_ctx.this = THIS; - if (heal_op == GF_AFR_OP_STATISTICS) - dict_foreach (rsp_dict, _heal_volume_add_shd_rsp_of_statistics, - &rsp_ctx); - else - dict_foreach (rsp_dict, _heal_volume_add_shd_rsp, &rsp_ctx); - - -out: - return ret; -} - -int -_status_volume_add_brick_rsp (dict_t *this, char *key, data_t *value, - void *data) -{ - char new_key[256] = {0,}; - data_t *new_value = 0; - glusterd_pr_brick_rsp_conv_t *rsp_ctx = NULL; - - rsp_ctx = data; - new_value = data_copy (value); - snprintf (new_key, sizeof (new_key), "brick%d.%s", rsp_ctx->count, key); - dict_set (rsp_ctx->dict, new_key, new_value); - - return 0; -} - -int -glusterd_status_volume_brick_rsp (dict_t *rsp_dict, dict_t *op_ctx, - char **op_errstr) -{ - int ret = 0; - glusterd_pr_brick_rsp_conv_t rsp_ctx = {0}; - int32_t count = 0; - int index = 0; - - GF_ASSERT (rsp_dict); - GF_ASSERT (op_ctx); - GF_ASSERT (op_errstr); - - ret = dict_get_int32 (op_ctx, "count", &count); - if (ret) { - count = 0; - } else { - count++; - } - ret = dict_get_int32 (rsp_dict, "index", &index); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Couldn't get node index"); - goto out; - } - dict_del (rsp_dict, "index"); - - rsp_ctx.count = index; - rsp_ctx.dict = op_ctx; - dict_foreach (rsp_dict, _status_volume_add_brick_rsp, &rsp_ctx); - ret = dict_set_int32 (op_ctx, "count", count); - -out: - return ret; -} - -int -glusterd_defrag_volume_node_rsp (dict_t *req_dict, dict_t *rsp_dict, - dict_t *op_ctx) -{ - int ret = 0; - char *volname = NULL; - glusterd_volinfo_t *volinfo = NULL; - char key[256] = {0,}; - int32_t i = 0; - char buf[1024] = {0,}; - char *node_str = NULL; - glusterd_conf_t *priv = NULL; - - priv = THIS->private; - GF_ASSERT (req_dict); - - ret = dict_get_str (req_dict, "volname", &volname); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); - goto out; - } - - ret = glusterd_volinfo_find (volname, &volinfo); - - if (ret) - goto out; - - if (rsp_dict) { - ret = glusterd_defrag_volume_status_update (volinfo, - rsp_dict); - } - - if (!op_ctx) { - dict_copy (rsp_dict, op_ctx); - goto out; - } - - ret = dict_get_int32 (op_ctx, "count", &i); - i++; - - ret = dict_set_int32 (op_ctx, "count", i); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, "Failed to set count"); - - snprintf (buf, 1024, "%s", uuid_utoa (MY_UUID)); - node_str = gf_strdup (buf); - - snprintf (key, 256, "node-uuid-%d",i); - ret = dict_set_dynstr (op_ctx, key, node_str); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set node-uuid"); - - memset (key, 0 , 256); - snprintf (key, 256, "files-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.rebalance_files); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set file count"); - - memset (key, 0 , 256); - snprintf (key, 256, "size-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.rebalance_data); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set size of xfer"); - - memset (key, 0 , 256); - snprintf (key, 256, "lookups-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.lookedup_files); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set lookedup file count"); - - memset (key, 0 , 256); - snprintf (key, 256, "status-%d", i); - ret = dict_set_int32 (op_ctx, key, volinfo->rebal.defrag_status); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set status"); - - memset (key, 0 , 256); - snprintf (key, 256, "failures-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.rebalance_failures); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set failure count"); - - memset (key, 0 , 256); - snprintf (key, 256, "skipped-%d", i); - ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.skipped_files); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set skipped count"); - - memset (key, 0, 256); - snprintf (key, 256, "run-time-%d", i); - ret = dict_set_double (op_ctx, key, volinfo->rebal.rebalance_time); - if (ret) - gf_log (THIS->name, GF_LOG_ERROR, - "failed to set run-time"); - -out: - return ret; -} -int32_t -glusterd_handle_node_rsp (dict_t *req_dict, void *pending_entry, - glusterd_op_t op, dict_t *rsp_dict, dict_t *op_ctx, - char **op_errstr, gd_node_type type) -{ - int ret = 0; - - GF_ASSERT (op_errstr); - - switch (op) { - case GD_OP_PROFILE_VOLUME: - ret = glusterd_profile_volume_brick_rsp (pending_entry, - rsp_dict, op_ctx, - op_errstr, type); - break; - case GD_OP_STATUS_VOLUME: - ret = glusterd_status_volume_brick_rsp (rsp_dict, op_ctx, - op_errstr); - break; - - case GD_OP_DEFRAG_BRICK_VOLUME: - glusterd_defrag_volume_node_rsp (req_dict, - rsp_dict, op_ctx); - break; - - case GD_OP_HEAL_VOLUME: - ret = glusterd_heal_volume_brick_rsp (req_dict, rsp_dict, - op_ctx, op_errstr); - break; - default: - break; - } - - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} - -int32_t -glusterd_set_originator_uuid (dict_t *dict) -{ - int ret = -1; - uuid_t *originator_uuid = NULL; - - GF_ASSERT (dict); - - originator_uuid = GF_CALLOC (1, sizeof(uuid_t), - gf_common_mt_uuid_t); - if (!originator_uuid) { - ret = -1; - goto out; - } - - uuid_copy (*originator_uuid, MY_UUID); - ret = dict_set_bin (dict, "originator_uuid", - originator_uuid, sizeof (uuid_t)); - if (ret) { - gf_log ("", GF_LOG_ERROR, - "Failed to set originator_uuid."); - goto out; - } - -out: - if (ret && originator_uuid) - GF_FREE (originator_uuid); - - return ret; -} - -/* Should be used only when an operation is in progress, as that is the only - * time a lock_owner is set - */ -gf_boolean_t -is_origin_glusterd (dict_t *dict) -{ - gf_boolean_t ret = _gf_false; - uuid_t lock_owner = {0,}; - uuid_t *originator_uuid = NULL; - - GF_ASSERT (dict); - - ret = dict_get_bin (dict, "originator_uuid", - (void **) &originator_uuid); - if (ret) { - /* If not originator_uuid has been set, then the command - * has been originated from a glusterd running on older version - * Hence fetching the lock owner */ - ret = glusterd_get_lock_owner (&lock_owner); - if (ret) { - ret = _gf_false; - goto out; - } - ret = !uuid_compare (MY_UUID, lock_owner); - } else - ret = !uuid_compare (MY_UUID, *originator_uuid); - -out: - return ret; -} - -int -glusterd_generate_and_set_task_id (dict_t *dict, char *key) -{ - int ret = -1; - uuid_t task_id = {0,}; - char *uuid_str = NULL; - xlator_t *this = NULL; - - GF_ASSERT (dict); - - this = THIS; - GF_ASSERT (this); - - uuid_generate (task_id); - uuid_str = gf_strdup (uuid_utoa (task_id)); - if (!uuid_str) { - ret = -1; - goto out; - } - - ret = dict_set_dynstr (dict, key, uuid_str); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set %s in dict", - key); - goto out; - } - gf_log (this->name, GF_LOG_INFO, "Generated task-id %s for key %s", - uuid_str, key); - -out: - if (ret) - GF_FREE (uuid_str); - return ret; -} - -int -glusterd_copy_uuid_to_dict (uuid_t uuid, dict_t *dict, char *key) -{ - int ret = -1; - char tmp_str[40] = {0,}; - char *task_id_str = NULL; - - GF_ASSERT (dict); - GF_ASSERT (key); - - uuid_unparse (uuid, tmp_str); - task_id_str = gf_strdup (tmp_str); - if (!task_id_str) - return -1; - - ret = dict_set_dynstr (dict, key, task_id_str); - if (ret) { - GF_FREE (task_id_str); - gf_log (THIS->name, GF_LOG_ERROR, - "Error setting uuid in dict with key %s", key); - } - - return 0; -} - -int -_update_volume_op_versions (dict_t *this, char *key, data_t *value, void *data) -{ - int op_version = 0; - glusterd_volinfo_t *ctx = NULL; - gf_boolean_t enabled = _gf_true; - int ret = -1; - - GF_ASSERT (data); - ctx = data; - - op_version = glusterd_get_op_version_for_key (key); - - if (gd_is_xlator_option (key) || gd_is_boolean_option (key)) { - ret = gf_string2boolean (value->data, &enabled); - if (ret) - return 0; - - if (!enabled) - return 0; - } - - if (op_version > ctx->op_version) - ctx->op_version = op_version; - - if (gd_is_client_option (key) && - (op_version > ctx->client_op_version)) - ctx->client_op_version = op_version; - - return 0; -} - -void -gd_update_volume_op_versions (glusterd_volinfo_t *volinfo) -{ - glusterd_conf_t *conf = NULL; - gf_boolean_t ob_enabled = _gf_false; - - GF_ASSERT (volinfo); - - conf = THIS->private; - GF_ASSERT (conf); - - /* Reset op-versions to minimum */ - volinfo->op_version = 1; - volinfo->client_op_version = 1; - - dict_foreach (volinfo->dict, _update_volume_op_versions, volinfo); - - /* Special case for open-behind - * If cluster op-version >= 2 and open-behind hasn't been explicitly - * disabled, volume op-versions must be updated to account for it - */ - - /* TODO: Remove once we have a general way to update automatically - * enabled features - */ - if (conf->op_version >= 2) { - ob_enabled = dict_get_str_boolean (volinfo->dict, - "performance.open-behind", - _gf_true); - if (ob_enabled) { - - if (volinfo->op_version < 2) - volinfo->op_version = 2; - if (volinfo->client_op_version < 2) - volinfo->client_op_version = 2; - } - } - - if (volinfo->type == GF_CLUSTER_TYPE_DISPERSE) { - if (volinfo->op_version < GD_OP_VERSION_3_6_0) - volinfo->op_version = GD_OP_VERSION_3_6_0; - if (volinfo->client_op_version < GD_OP_VERSION_3_6_0) - volinfo->client_op_version = GD_OP_VERSION_3_6_0; - } - - return; -} - -int -op_version_check (xlator_t *this, int min_op_version, char *msg, int msglen) -{ - int ret = 0; - glusterd_conf_t *priv = NULL; - - GF_ASSERT (this); - GF_ASSERT (msg); - - priv = this->private; - if (priv->op_version < min_op_version) { - snprintf (msg, msglen, "One or more nodes do not support " - "the required op-version. Cluster op-version must " - "atleast be %d.", min_op_version); - gf_log (this->name, GF_LOG_ERROR, "%s", msg); - ret = -1; - } - return ret; -} - - -/* A task is committed/completed once the task-id for it is cleared */ -gf_boolean_t -gd_is_remove_brick_committed (glusterd_volinfo_t *volinfo) -{ - GF_ASSERT (volinfo); - - if ((GD_OP_REMOVE_BRICK == volinfo->rebal.op) && - !uuid_is_null (volinfo->rebal.rebalance_id)) - return _gf_false; - - return _gf_true; -} - -gf_boolean_t -glusterd_is_status_tasks_op (glusterd_op_t op, dict_t *dict) -{ - int ret = -1; - uint32_t cmd = GF_CLI_STATUS_NONE; - gf_boolean_t is_status_tasks = _gf_false; - - if (op != GD_OP_STATUS_VOLUME) - goto out; - - ret = dict_get_uint32 (dict, "cmd", &cmd); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Failed to get opcode"); - goto out; - } - - if (cmd & GF_CLI_STATUS_TASKS) - is_status_tasks = _gf_true; - -out: - return is_status_tasks; -} - -int -glusterd_compare_snap_time(struct list_head *list1, struct list_head *list2) -{ - glusterd_snap_t *snap1 = NULL; - glusterd_snap_t *snap2 = NULL; - double diff_time = 0; - - GF_ASSERT (list1); - GF_ASSERT (list2); - - snap1 = list_entry(list1, glusterd_snap_t, snap_list); - snap2 = list_entry(list2, glusterd_snap_t, snap_list); - diff_time = difftime(snap1->time_stamp, snap2->time_stamp); - - return ((int)diff_time); -} - -int -glusterd_compare_snap_vol_time(struct list_head *list1, struct list_head *list2) -{ - glusterd_volinfo_t *snapvol1 = NULL; - glusterd_volinfo_t *snapvol2 = NULL; - double diff_time = 0; - - GF_ASSERT (list1); - GF_ASSERT (list2); - - snapvol1 = list_entry(list1, glusterd_volinfo_t, snapvol_list); - snapvol2 = list_entry(list2, glusterd_volinfo_t, snapvol_list); - diff_time = difftime(snapvol1->snapshot->time_stamp, - snapvol2->snapshot->time_stamp); - - return ((int)diff_time); -} - -int32_t -glusterd_missed_snapinfo_new (glusterd_missed_snap_info **missed_snapinfo) -{ - glusterd_missed_snap_info *new_missed_snapinfo = NULL; - int32_t ret = -1; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (missed_snapinfo); - - new_missed_snapinfo = GF_CALLOC (1, sizeof(*new_missed_snapinfo), - gf_gld_mt_missed_snapinfo_t); - - if (!new_missed_snapinfo) - goto out; - - INIT_LIST_HEAD (&new_missed_snapinfo->missed_snaps); - INIT_LIST_HEAD (&new_missed_snapinfo->snap_ops); - - *missed_snapinfo = new_missed_snapinfo; - - ret = 0; - -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -int32_t -glusterd_missed_snap_op_new (glusterd_snap_op_t **snap_op) -{ - glusterd_snap_op_t *new_snap_op = NULL; - int32_t ret = -1; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (snap_op); - - new_snap_op = GF_CALLOC (1, sizeof(*new_snap_op), - gf_gld_mt_missed_snapinfo_t); - - if (!new_snap_op) - goto out; - - new_snap_op->brick_num = -1; - new_snap_op->op = -1; - new_snap_op->status = -1; - INIT_LIST_HEAD (&new_snap_op->snap_ops_list); - - *snap_op = new_snap_op; - - ret = 0; -out: - gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); - return ret; -} - -/* Tells if rebalance needs to be started for the given volume on the peer - * - * Rebalance should be started on a peer only if an involved brick is present on - * the peer. - * - * For a normal rebalance, if any one brick of the given volume is present on - * the peer, the rebalance process should be started. - * - * For a rebalance as part of a remove-brick operation, the rebalance process - * should be started only if one of the bricks being removed is present on the - * peer - */ -gf_boolean_t -gd_should_i_start_rebalance (glusterd_volinfo_t *volinfo) { - gf_boolean_t retval = _gf_false; - int ret = -1; - glusterd_brickinfo_t *brick = NULL; - int count = 0; - int i = 0; - char key[1023] = {0,}; - char *brickname = NULL; - - - switch (volinfo->rebal.op) { - case GD_OP_REBALANCE: - list_for_each_entry (brick, &volinfo->bricks, brick_list) { - if (uuid_compare (MY_UUID, brick->uuid) == 0) { - retval = _gf_true; - break; - } - } - break; - case GD_OP_REMOVE_BRICK: - ret = dict_get_int32 (volinfo->rebal.dict, "count", &count); - if (ret) { - goto out; - } - for (i = 1; i <= count; i++) { - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "brick%d", i); - ret = dict_get_str (volinfo->rebal.dict, key, - &brickname); - if (ret) - goto out; - ret = glusterd_volume_brickinfo_get_by_brick (brickname, - volinfo, - &brick); - if (ret) - goto out; - if (uuid_compare (MY_UUID, brick->uuid) == 0) { - retval = _gf_true; - break; - } - } - break; - default: - break; - } - -out: - return retval; -} - -int -glusterd_is_volume_quota_enabled (glusterd_volinfo_t *volinfo) -{ - return (glusterd_volinfo_get_boolean (volinfo, VKEY_FEATURES_QUOTA)); -} - -int -glusterd_validate_and_set_gfid (dict_t *op_ctx, dict_t *req_dict, - char **op_errstr) -{ - int ret = -1; - int count = 0; - int i = 0; - int op_code = GF_QUOTA_OPTION_TYPE_NONE; - uuid_t uuid1 = {0}; - uuid_t uuid2 = {0,}; - char *path = NULL; - char key[256] = {0,}; - char *uuid1_str = NULL; - char *uuid1_str_dup = NULL; - char *uuid2_str = NULL; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - - ret = dict_get_int32 (op_ctx, "type", &op_code); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get quota opcode"); - goto out; - } - - if ((op_code != GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) && - (op_code != GF_QUOTA_OPTION_TYPE_REMOVE)) { - ret = 0; - goto out; - } - - ret = dict_get_str (op_ctx, "path", &path); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get path"); - goto out; - } - - ret = dict_get_int32 (op_ctx, "count", &count); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get count"); - goto out; - } - - /* If count is 0, fail the command with ENOENT. - * - * If count is 1, treat gfid0 as the gfid on which the operation - * is to be performed and resume the command. - * - * if count > 1, get the 0th gfid from the op_ctx and, - * compare it with the remaining 'count -1' gfids. - * If they are found to be the same, set gfid0 in the op_ctx and - * resume the operation, else error out. - */ - - if (count == 0) { - gf_asprintf (op_errstr, "Failed to get trusted.gfid attribute " - "on path %s. Reason : %s", path, - strerror (ENOENT)); - ret = -1; - goto out; - } - - snprintf (key, sizeof (key) - 1, "gfid%d", 0); - - ret = dict_get_str (op_ctx, key, &uuid1_str); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get key '%s'", - key); - goto out; + ret = dict_set_uint64 (ctx_dict, key, value); + if (ret) { + gf_log (THIS->name, GF_LOG_DEBUG, + "failed to set lookuped file count"); + } } - uuid_parse (uuid1_str, uuid1); - - for (i = 1; i < count; i++) { - snprintf (key, sizeof (key)-1, "gfid%d", i); - - ret = dict_get_str (op_ctx, key, &uuid2_str); + memset (key, 0, 256); + snprintf (key, 256, "status-%d", index); + ret = dict_get_int32 (rsp_dict, key, &value32); + if (!ret) { + memset (key, 0, 256); + snprintf (key, 256, "status-%d", current_index); + ret = dict_set_int32 (ctx_dict, key, value32); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get key " - "'%s'", key); - goto out; + gf_log (THIS->name, GF_LOG_DEBUG, + "failed to set status"); } + } - uuid_parse (uuid2_str, uuid2); - - if (uuid_compare (uuid1, uuid2)) { - gf_asprintf (op_errstr, "gfid mismatch between %s and " - "%s for path %s", uuid1_str, uuid2_str, - path); - ret = -1; - goto out; + memset (key, 0, 256); + snprintf (key, 256, "failures-%d", index); + ret = dict_get_uint64 (rsp_dict, key, &value); + if (!ret) { + memset (key, 0, 256); + snprintf (key, 256, "failures-%d", current_index); + ret = dict_set_uint64 (ctx_dict, key, value); + if (ret) { + gf_log (THIS->name, GF_LOG_DEBUG, + "failed to set failure count"); } } - if (i == count) { - uuid1_str_dup = gf_strdup (uuid1_str); - if (!uuid1_str_dup) { - ret = -1; - goto out; + memset (key, 0, 256); + snprintf (key, 256, "skipped-%d", index); + ret = dict_get_uint64 (rsp_dict, key, &value); + if (!ret) { + memset (key, 0, 256); + snprintf (key, 256, "skipped-%d", current_index); + ret = dict_set_uint64 (ctx_dict, key, value); + if (ret) { + gf_log (THIS->name, GF_LOG_DEBUG, + "failed to set skipped count"); } - - ret = dict_set_dynstr (req_dict, "gfid", uuid1_str_dup); + } + memset (key, 0, 256); + snprintf (key, 256, "run-time-%d", index); + ret = dict_get_double (rsp_dict, key, &elapsed_time); + if (!ret) { + memset (key, 0, 256); + snprintf (key, 256, "run-time-%d", current_index); + ret = dict_set_double (ctx_dict, key, elapsed_time); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to set gfid"); - GF_FREE (uuid1_str_dup); - goto out; + gf_log (THIS->name, GF_LOG_DEBUG, + "failed to set run-time"); } - } else { - gf_log (this->name, GF_LOG_ERROR, "Failed to iterate through %d" - " entries in the req dict", count); - ret = -1; - goto out; } ret = 0; + out: return ret; } -void -glusterd_clean_up_quota_store (glusterd_volinfo_t *volinfo) +int +glusterd_sys_exec_output_rsp_dict (dict_t *dst, dict_t *src) { - char voldir[PATH_MAX] = {0,}; - char quota_confpath[PATH_MAX] = {0,}; - char cksum_path[PATH_MAX] = {0,}; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; - - this = THIS; - GF_ASSERT (this); - conf = this->private; - GF_ASSERT (conf); - - GLUSTERD_GET_VOLUME_DIR (voldir, volinfo, conf); - - snprintf (quota_confpath, sizeof (quota_confpath), "%s/%s", voldir, - GLUSTERD_VOLUME_QUOTA_CONFIG); - snprintf (cksum_path, sizeof (cksum_path), "%s/%s", voldir, - GLUSTERD_VOL_QUOTA_CKSUM_FILE); - - unlink (quota_confpath); - unlink (cksum_path); - - gf_store_handle_destroy (volinfo->quota_conf_shandle); - volinfo->quota_conf_shandle = NULL; - volinfo->quota_conf_version = 0; - -} + char output_name[PATH_MAX] = ""; + char *output = NULL; + int ret = 0; + int i = 0; + int len = 0; + int src_output_count = 0; + int dst_output_count = 0; -#define QUOTA_CONF_HEADER \ - "GlusterFS Quota conf | version: v%d.%d\n" + if (!dst || !src) { + gf_log ("", GF_LOG_ERROR, "Source or Destination " + "dict is empty."); + goto out; + } -int -glusterd_store_quota_conf_skip_header (xlator_t *this, int fd) -{ - char buf[PATH_MAX] = {0,}; + ret = dict_get_int32 (dst, "output_count", &dst_output_count); - snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); - return gf_skip_header_section (fd, strlen (buf)); -} + ret = dict_get_int32 (src, "output_count", &src_output_count); + if (ret) { + gf_log ("", GF_LOG_DEBUG, "No output from source"); + ret = 0; + goto out; + } -int -glusterd_store_quota_conf_stamp_header (xlator_t *this, int fd) -{ - char buf[PATH_MAX] = {0,}; - int buf_len = 0; - ssize_t ret = -1; - ssize_t written = 0; + for (i = 1; i <= src_output_count; i++) { + len = snprintf (output_name, sizeof(output_name) - 1, + "output_%d", i); + output_name[len] = '\0'; + ret = dict_get_str (src, output_name, &output); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch %s", + output_name); + goto out; + } - snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); - buf_len = strlen (buf); - for (written = 0; written != buf_len; written += ret) { - ret = write (fd, buf + written, buf_len - written); - if (ret == -1) { + len = snprintf (output_name, sizeof(output_name) - 1, + "output_%d", i+dst_output_count); + output_name[len] = '\0'; + ret = dict_set_dynstr (dst, output_name, gf_strdup (output)); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set %s", + output_name); goto out; } } - ret = 0; + ret = dict_set_int32 (dst, "output_count", + dst_output_count+src_output_count); out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } int -glusterd_remove_auxiliary_mount (char *volname) -{ - int ret = -1; - char mountdir[PATH_MAX] = {0,}; - char pidfile[PATH_MAX] = {0,}; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - - GLUSTERFS_GET_AUX_MOUNT_PIDFILE (pidfile, volname); - - if (!gf_is_service_running (pidfile, NULL)) { - gf_log (this->name, GF_LOG_DEBUG, "Aux mount of volume %s " - "absent, hence returning", volname); - return 0; - } - - GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mountdir, volname, "/"); - ret = gf_umount_lazy (this->name, mountdir, 1); - if (ret) - gf_log (this->name, GF_LOG_ERROR, "umount on %s failed, " - "reason : %s", mountdir, strerror (errno)); - - return ret; -} - -/* Stops the rebalance process of the given volume - */ -int -gd_stop_rebalance_process (glusterd_volinfo_t *volinfo) -{ - int ret = -1; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; - char pidfile[PATH_MAX] = {0,}; - - GF_ASSERT (volinfo); - - this = THIS; - GF_ASSERT (this); - - conf = this->private; - GF_ASSERT (conf); - - GLUSTERD_GET_DEFRAG_PID_FILE (pidfile, volinfo, conf); - ret = glusterd_service_stop ("rebalance", pidfile, SIGTERM, _gf_true); - - return ret; -} - -rpc_clnt_t * -glusterd_rpc_clnt_unref (glusterd_conf_t *conf, rpc_clnt_t *rpc) -{ - rpc_clnt_t *ret = NULL; - - GF_ASSERT (conf); - GF_ASSERT (rpc); - synclock_unlock (&conf->big_lock); - ret = rpc_clnt_unref (rpc); - synclock_lock (&conf->big_lock); - - return ret; -} - -int32_t -glusterd_compare_volume_name(struct list_head *list1, struct list_head *list2) -{ - glusterd_volinfo_t *volinfo1 = NULL; - glusterd_volinfo_t *volinfo2 = NULL; - - volinfo1 = list_entry(list1, glusterd_volinfo_t, vol_list); - volinfo2 = list_entry(list2, glusterd_volinfo_t, vol_list); - return strcmp(volinfo1->volname, volinfo2->volname); -} - -int32_t -glusterd_mount_lvm_snapshot (glusterd_brickinfo_t *brickinfo, - char *brick_mount_path) +glusterd_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict) { - char msg[NAME_MAX] = ""; - char mnt_opts[1024] = ""; - int32_t ret = -1; - runner_t runner = {0, }; - xlator_t *this = NULL; + int ret = 0; + glusterd_op_t op = GD_OP_NONE; - this = THIS; - GF_ASSERT (this); - GF_ASSERT (brick_mount_path); - GF_ASSERT (brickinfo); + op = glusterd_op_get_op (); + GF_ASSERT (aggr); + GF_ASSERT (rsp_dict); + if (!aggr) + goto out; + dict_copy (rsp_dict, aggr); +out: + return ret; +} - runinit (&runner); - snprintf (msg, sizeof (msg), "mount %s %s", - brickinfo->device_path, brick_mount_path); +int +glusterd_volume_heal_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict) +{ + int ret = 0; + dict_t *ctx_dict = NULL; + glusterd_op_t op = GD_OP_NONE; - strcpy (mnt_opts, brickinfo->mnt_opts); + GF_ASSERT (rsp_dict); - /* XFS file-system does not allow to mount file-system with duplicate - * UUID. File-system UUID of snapshot and its origin volume is same. - * Therefore to mount such a snapshot in XFS we need to pass nouuid - * option - */ - if (!strcmp (brickinfo->fstype, "xfs") && - !mntopts_exists (mnt_opts, "nouuid")) { - if ( strlen (mnt_opts) > 0 ) - strcat (mnt_opts, ","); - strcat (mnt_opts, "nouuid"); - } + op = glusterd_op_get_op (); + GF_ASSERT (GD_OP_HEAL_VOLUME == op); + if (aggr) { + ctx_dict = aggr; - if ( strlen (mnt_opts) > 0 ) { - runner_add_args (&runner, "mount", "-o", mnt_opts, - brickinfo->device_path, brick_mount_path, NULL); } else { - runner_add_args (&runner, "mount", brickinfo->device_path, - brick_mount_path, NULL); + ctx_dict = glusterd_op_get_ctx (op); } - runner_log (&runner, this->name, GF_LOG_DEBUG, msg); - ret = runner_run (&runner); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "mounting the snapshot " - "logical device %s failed (error: %s)", - brickinfo->device_path, strerror (errno)); + if (!ctx_dict) goto out; - } else - gf_log (this->name, GF_LOG_DEBUG, "mounting the snapshot " - "logical device %s successful", brickinfo->device_path); - + dict_copy (rsp_dict, ctx_dict); out: - gf_log (this->name, GF_LOG_TRACE, "Returning with %d", ret); return ret; } -int32_t -glusterd_umount (const char *path) +int +_profile_volume_add_brick_rsp (dict_t *this, char *key, data_t *value, + void *data) { - char msg[NAME_MAX] = ""; - int32_t ret = -1; - runner_t runner = {0, }; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - GF_ASSERT (path); - - runinit (&runner); - snprintf (msg, sizeof (msg), "umount path %s", path); - runner_add_args (&runner, _PATH_UMOUNT, "-f", path, NULL); - runner_log (&runner, this->name, GF_LOG_DEBUG, msg); - ret = runner_run (&runner); - if (ret) - gf_log (this->name, GF_LOG_ERROR, "umounting %s failed (%s)", - path, strerror (errno)); + char new_key[256] = {0}; + glusterd_pr_brick_rsp_conv_t *rsp_ctx = NULL; + data_t *new_value = NULL; - gf_log (this->name, GF_LOG_TRACE, "Returning with %d", ret); - return ret; + rsp_ctx = data; + new_value = data_copy (value); + GF_ASSERT (new_value); + snprintf (new_key, sizeof (new_key), "%d-%s", rsp_ctx->count, key); + dict_set (rsp_ctx->dict, new_key, new_value); + return 0; } -int32_t -glusterd_copy_file (const char *source, const char *destination) +int +glusterd_volume_quota_copy_to_op_ctx_dict (dict_t *dict, dict_t *rsp_dict) { - int32_t ret = -1; - xlator_t *this = NULL; - char buffer[1024] = ""; - int src_fd = -1; - int dest_fd = -1; - int read_len = -1; - struct stat stbuf = {0,}; - mode_t dest_mode = 0; + int ret = -1; + int i = 0; + int count = 0; + int rsp_dict_count = 0; + char *uuid_str = NULL; + char *uuid_str_dup = NULL; + char key[256] = {0,}; + xlator_t *this = NULL; + int type = GF_QUOTA_OPTION_TYPE_NONE; this = THIS; GF_ASSERT (this); - GF_ASSERT (source); - GF_ASSERT (destination); - - /* Here is stat is made to get the file permission of source file*/ - ret = lstat (source, &stbuf); + ret = dict_get_int32 (dict, "type", &type); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "%s not found", source); + gf_log (this->name, GF_LOG_ERROR, "Failed to get quota opcode"); goto out; } - dest_mode = stbuf.st_mode & 0777; - - src_fd = open (source, O_RDONLY); - if (src_fd < 0) { - ret = -1; - gf_log (this->name, GF_LOG_ERROR, "Unable to open file %s", - source); + if ((type != GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) && + (type != GF_QUOTA_OPTION_TYPE_REMOVE)) { + dict_copy (rsp_dict, dict); + ret = 0; goto out; } - dest_fd = open (destination, O_CREAT | O_RDWR, dest_mode); - if (dest_fd < 0) { - ret = -1; - gf_log (this->name, GF_LOG_ERROR, - "Unble to open a file %s", destination); + ret = dict_get_int32 (rsp_dict, "count", &rsp_dict_count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get the count of " + "gfids from the rsp dict"); goto out; } - do { - ret = read (src_fd, buffer, sizeof (buffer)); - if (ret == -1) { - gf_log (this->name, GF_LOG_ERROR, "Error reading file " - "%s", source); + ret = dict_get_int32 (dict, "count", &count); + if (ret) + /* The key "count" is absent in op_ctx when this function is + * called after self-staging on the originator. This must not + * be treated as error. + */ + gf_log (this->name, GF_LOG_DEBUG, "Failed to get count of gfids" + " from req dict. This could be because count is not yet" + " copied from rsp_dict into op_ctx"); + + for (i = 0; i < rsp_dict_count; i++) { + snprintf (key, sizeof(key)-1, "gfid%d", i); + + ret = dict_get_str (rsp_dict, key, &uuid_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get gfid " + "from rsp dict"); goto out; } - read_len = ret; - if (read_len == 0) - break; - ret = write (dest_fd, buffer, read_len); - if (ret != read_len) { - gf_log (this->name, GF_LOG_ERROR, "Error writing in " - "file %s", destination); + snprintf (key, sizeof (key)-1, "gfid%d", i + count); + + uuid_str_dup = gf_strdup (uuid_str); + if (!uuid_str_dup) { + ret = -1; + goto out; + } + + ret = dict_set_dynstr (dict, key, uuid_str_dup); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set gfid " + "from rsp dict into req dict"); + GF_FREE (uuid_str_dup); goto out; } - } while (ret > 0); -out : - if (src_fd > 0) - close (src_fd); + } + + ret = dict_set_int32 (dict, "count", rsp_dict_count + count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set aggregated " + "count in req dict"); + goto out; + } - if (dest_fd > 0) - close (dest_fd); +out: return ret; } -int32_t -glusterd_copy_folder (const char *source, const char *destination) +int +glusterd_profile_volume_brick_rsp (void *pending_entry, + dict_t *rsp_dict, dict_t *op_ctx, + char **op_errstr, gd_node_type type) { - DIR *dir_ptr = NULL; - struct dirent *direntp = NULL; - int32_t ret = -1; - char src_path[PATH_MAX] = ""; - char dest_path[PATH_MAX] = ""; - xlator_t *this = NULL; + int ret = 0; + glusterd_pr_brick_rsp_conv_t rsp_ctx = {0}; + int32_t count = 0; + char brick[PATH_MAX+1024] = {0}; + char key[256] = {0}; + char *full_brick = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + + GF_ASSERT (rsp_dict); + GF_ASSERT (op_ctx); + GF_ASSERT (op_errstr); + GF_ASSERT (pending_entry); this = THIS; GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); - GF_ASSERT (source); - GF_ASSERT (destination); - - dir_ptr = opendir (source); - if (!dir_ptr) { - gf_log (this->name, GF_LOG_ERROR, "Unable to open %s", source); - goto out; + ret = dict_get_int32 (op_ctx, "count", &count); + if (ret) { + count = 1; + } else { + count++; } - - while ((direntp = readdir (dir_ptr)) != NULL) { - if (strcmp (direntp->d_name, ".") == 0 || - strcmp (direntp->d_name, "..") == 0) - continue; - ret = snprintf (src_path, sizeof (src_path), "%s/%s", - source, direntp->d_name); - if (ret < 0) - goto out; - - ret = snprintf (dest_path, sizeof (dest_path), "%s/%s", - destination, direntp->d_name); - if (ret < 0) - goto out; - - ret = glusterd_copy_file (src_path, dest_path); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Could not copy " - "%s to %s", src_path, dest_path); - goto out; - } + snprintf (key, sizeof (key), "%d-brick", count); + if (type == GD_NODE_BRICK) { + brickinfo = pending_entry; + snprintf (brick, sizeof (brick), "%s:%s", brickinfo->hostname, + brickinfo->path); + } else if (type == GD_NODE_NFS) { + snprintf (brick, sizeof (brick), "%s", uuid_utoa (MY_UUID)); } -out: - if (dir_ptr) - closedir (dir_ptr); + full_brick = gf_strdup (brick); + GF_ASSERT (full_brick); + ret = dict_set_dynstr (op_ctx, key, full_brick); + rsp_ctx.count = count; + rsp_ctx.dict = op_ctx; + dict_foreach (rsp_dict, _profile_volume_add_brick_rsp, &rsp_ctx); + dict_del (op_ctx, "count"); + ret = dict_set_int32 (op_ctx, "count", count); return ret; } -int32_t -glusterd_get_geo_rep_session (char *slave_key, char *origin_volname, - dict_t *gsync_slaves_dict, char *session, - char *slave) -{ - int32_t ret = -1; - char *token = NULL; - char *temp = NULL; - char *ip = NULL; - char *buffer = NULL; - xlator_t *this = NULL; - char *slave_temp = NULL; - char *save_ptr = NULL; +//input-key: :-* +//output-key: -* +int +_heal_volume_add_shd_rsp (dict_t *this, char *key, data_t *value, void *data) +{ + char new_key[256] = {0,}; + char int_str[16] = {0}; + data_t *new_value = NULL; + char *rxl_end = NULL; + char *rxl_child_end = NULL; + glusterd_volinfo_t *volinfo = NULL; + int rxl_id = 0; + int rxl_child_id = 0; + int brick_id = 0; + int int_len = 0; + int ret = 0; + glusterd_heal_rsp_conv_t *rsp_ctx = NULL; + glusterd_brickinfo_t *brickinfo = NULL; - this = THIS; - GF_ASSERT (this); + rsp_ctx = data; + rxl_end = strchr (key, '-'); + if (!rxl_end) + goto out; - GF_ASSERT (slave_key); - GF_ASSERT (origin_volname); - GF_ASSERT (gsync_slaves_dict); + int_len = strlen (key) - strlen (rxl_end); + strncpy (int_str, key, int_len); + int_str[int_len] = '\0'; + ret = gf_string2int (int_str, &rxl_id); + if (ret) + goto out; - ret = dict_get_str (gsync_slaves_dict, slave_key, &buffer); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to " - "get value for key %s", slave_key); + rxl_child_end = strchr (rxl_end + 1, '-'); + if (!rxl_child_end) goto out; - } - temp = gf_strdup (buffer); - if (!temp) { - ret = -1; + int_len = strlen (rxl_end) - strlen (rxl_child_end) - 1; + strncpy (int_str, rxl_end + 1, int_len); + int_str[int_len] = '\0'; + ret = gf_string2int (int_str, &rxl_child_id); + if (ret) goto out; + + volinfo = rsp_ctx->volinfo; + brick_id = rxl_id * volinfo->replica_count + rxl_child_id; + + if (!strcmp (rxl_child_end, "-status")) { + brickinfo = glusterd_get_brickinfo_by_position (volinfo, + brick_id); + if (!brickinfo) + goto out; + if (!glusterd_is_local_brick (rsp_ctx->this, volinfo, + brickinfo)) + goto out; } + new_value = data_copy (value); + snprintf (new_key, sizeof (new_key), "%d%s", brick_id, rxl_child_end); + dict_set (rsp_ctx->dict, new_key, new_value); + +out: + return 0; +} + +int +_heal_volume_add_shd_rsp_of_statistics (dict_t *this, char *key, data_t + *value, void *data) +{ + char new_key[256] = {0,}; + char int_str[16] = {0,}; + char key_begin_string[128] = {0,}; + data_t *new_value = NULL; + char *rxl_end = NULL; + char *rxl_child_end = NULL; + glusterd_volinfo_t *volinfo = NULL; + char *key_begin_str = NULL; + int rxl_id = 0; + int rxl_child_id = 0; + int brick_id = 0; + int int_len = 0; + int ret = 0; + glusterd_heal_rsp_conv_t *rsp_ctx = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + + rsp_ctx = data; + key_begin_str = strchr (key, '-'); + if (!key_begin_str) + goto out; - token = strtok_r (temp, "/", &save_ptr); + int_len = strlen (key) - strlen (key_begin_str); + strncpy (key_begin_string, key, int_len); + key_begin_string[int_len] = '\0'; - token = strtok_r (NULL, ":", &save_ptr); - if (!token) { - ret = -1; + rxl_end = strchr (key_begin_str + 1, '-'); + if (!rxl_end) goto out; - } - token++; - ip = gf_strdup (token); - if (!ip) { - ret = -1; + int_len = strlen (key_begin_str) - strlen (rxl_end) - 1; + strncpy (int_str, key_begin_str + 1, int_len); + int_str[int_len] = '\0'; + ret = gf_string2int (int_str, &rxl_id); + if (ret) goto out; - } - token = strtok_r (NULL, "\0", &save_ptr); - if (!token) { - ret = -1; - goto out; - } - token++; - slave_temp = gf_strdup (token); - if (!slave) { - ret = -1; + rxl_child_end = strchr (rxl_end + 1, '-'); + if (!rxl_child_end) goto out; - } - ret = snprintf (session, PATH_MAX, "%s_%s_%s", - origin_volname, ip, slave_temp); - if (ret < 0) /* Negative value is an error */ + int_len = strlen (rxl_end) - strlen (rxl_child_end) - 1; + strncpy (int_str, rxl_end + 1, int_len); + int_str[int_len] = '\0'; + ret = gf_string2int (int_str, &rxl_child_id); + if (ret) goto out; - ret = snprintf (slave, PATH_MAX, "%s::%s", ip, slave_temp); - if (ret < 0) { + volinfo = rsp_ctx->volinfo; + brick_id = rxl_id * volinfo->replica_count + rxl_child_id; + + brickinfo = glusterd_get_brickinfo_by_position (volinfo, brick_id); + if (!brickinfo) + goto out; + if (!glusterd_is_local_brick (rsp_ctx->this, volinfo, brickinfo)) goto out; - } - ret = 0; /* Success */ + new_value = data_copy (value); + snprintf (new_key, sizeof (new_key), "%s-%d%s", key_begin_string, + brick_id, rxl_child_end); + dict_set (rsp_ctx->dict, new_key, new_value); out: - if (temp) - GF_FREE (temp); - - if (ip) - GF_FREE (ip); - - if (slave_temp) - GF_FREE (slave_temp); + return 0; - return ret; } -int32_t -glusterd_copy_quota_files (glusterd_volinfo_t *src_vol, - glusterd_volinfo_t *dest_vol) { - - int32_t ret = -1; - char src_dir[PATH_MAX] = ""; - char dest_dir[PATH_MAX] = ""; - char src_path[PATH_MAX] = ""; - char dest_path[PATH_MAX] = ""; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - struct stat stbuf = {0,}; - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - - GF_ASSERT (src_vol); - GF_ASSERT (dest_vol); - - GLUSTERD_GET_VOLUME_DIR (src_dir, src_vol, priv); - - GLUSTERD_GET_VOLUME_DIR (dest_dir, dest_vol, priv); +int +glusterd_heal_volume_brick_rsp (dict_t *req_dict, dict_t *rsp_dict, + dict_t *op_ctx, char **op_errstr) +{ + int ret = 0; + glusterd_heal_rsp_conv_t rsp_ctx = {0}; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + int heal_op = -1; - ret = snprintf (src_path, sizeof (src_path), "%s/quota.conf", - src_dir); - if (ret < 0) - goto out; + GF_ASSERT (rsp_dict); + GF_ASSERT (op_ctx); + GF_ASSERT (op_errstr); - /* quota.conf is not present if quota is not enabled, Hence ignoring - * the absence of this file - */ - ret = lstat (src_path, &stbuf); + ret = dict_get_str (req_dict, "volname", &volname); if (ret) { - ret = 0; - gf_log (this->name, GF_LOG_DEBUG, "%s not found", src_path); + gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } - ret = snprintf (dest_path, sizeof (dest_path), "%s/quota.conf", - dest_dir); - if (ret < 0) - goto out; - - ret = glusterd_copy_file (src_path, dest_path); + ret = dict_get_int32 (req_dict, "heal-op", &heal_op); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to copy %s in %s", - src_path, dest_path); + gf_log ("", GF_LOG_ERROR, "Unable to get heal_op"); goto out; } - ret = snprintf (src_path, sizeof (src_path), "%s/quota.cksum", - src_dir); - if (ret < 0) - goto out; - /* If quota.conf is present and quota.cksum is not present, then - * that scenario is considered as invalid, hence error out. - */ - ret = lstat (src_path, &stbuf); - if (ret) { - ret = -1; - gf_log (this->name, GF_LOG_ERROR, "%s not found", src_path); - goto out; - } + ret = glusterd_volinfo_find (volname, &volinfo); - ret = snprintf (dest_path, sizeof (dest_path), "%s/quota.cksum", - dest_dir); - if (ret < 0) + if (ret) goto out; - ret = glusterd_copy_file (src_path, dest_path); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to copy %s in %s", - src_path, dest_path); - goto out; - } + rsp_ctx.dict = op_ctx; + rsp_ctx.volinfo = volinfo; + rsp_ctx.this = THIS; + if (heal_op == GF_AFR_OP_STATISTICS) + dict_foreach (rsp_dict, _heal_volume_add_shd_rsp_of_statistics, + &rsp_ctx); + else + dict_foreach (rsp_dict, _heal_volume_add_shd_rsp, &rsp_ctx); + out: return ret; - } -int32_t -glusterd_restore_geo_rep_files (glusterd_volinfo_t *snap_vol) -{ - int32_t ret = -1; - char src_path[PATH_MAX] = ""; - char dest_path[PATH_MAX] = ""; - xlator_t *this = NULL; - char *origin_volname = NULL; - glusterd_volinfo_t *origin_vol = NULL; - int i = 0; - char key[PATH_MAX] = ""; - char session[PATH_MAX] = ""; - char slave[PATH_MAX] = ""; - char snapgeo_dir[PATH_MAX] = ""; - glusterd_conf_t *priv = NULL; +int +_status_volume_add_brick_rsp (dict_t *this, char *key, data_t *value, + void *data) +{ + char new_key[256] = {0,}; + data_t *new_value = 0; + glusterd_pr_brick_rsp_conv_t *rsp_ctx = NULL; - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); + rsp_ctx = data; + new_value = data_copy (value); + snprintf (new_key, sizeof (new_key), "brick%d.%s", rsp_ctx->count, key); + dict_set (rsp_ctx->dict, new_key, new_value); - GF_ASSERT (snap_vol); + return 0; +} - origin_volname = gf_strdup (snap_vol->parent_volname); - if (!origin_volname) { - ret = -1; - goto out; - } +int +glusterd_status_volume_brick_rsp (dict_t *rsp_dict, dict_t *op_ctx, + char **op_errstr) +{ + int ret = 0; + glusterd_pr_brick_rsp_conv_t rsp_ctx = {0}; + int32_t count = 0; + int index = 0; + + GF_ASSERT (rsp_dict); + GF_ASSERT (op_ctx); + GF_ASSERT (op_errstr); - ret = glusterd_volinfo_find (origin_volname, &origin_vol); + ret = dict_get_int32 (op_ctx, "count", &count); + if (ret) { + count = 0; + } else { + count++; + } + ret = dict_get_int32 (rsp_dict, "index", &index); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Unable to fetch " - "volinfo for volname %s", origin_volname); + gf_log (THIS->name, GF_LOG_ERROR, "Couldn't get node index"); goto out; } + dict_del (rsp_dict, "index"); - for (i = 1 ; i <= snap_vol->gsync_slaves->count; i++) { - ret = snprintf (key, sizeof (key), "slave%d", i); - if (ret < 0) { - goto out; - } - - /* "origin_vol" is used here because geo-replication saves - * the session in the form of master_ip_slave. - * As we need the master volume to be same even after - * restore, we are passing the origin volume name. - * - * "snap_vol->gsync_slaves" contain the slave information - * when the snapshot was taken, hence we have to restore all - * those slaves information when we do snapshot restore. - */ - ret = glusterd_get_geo_rep_session (key, origin_vol->volname, - snap_vol->gsync_slaves, - session, slave); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Failed to get geo-rep session"); - goto out; - } - - GLUSTERD_GET_SNAP_GEO_REP_DIR(snapgeo_dir, snap_vol->snapshot, - priv); - ret = snprintf (src_path, sizeof (src_path), - "%s/%s", snapgeo_dir, session); - if (ret < 0) - goto out; - - ret = snprintf (dest_path, sizeof (dest_path), - "%s/%s/%s", priv->workdir, GEOREP, - session); - if (ret < 0) - goto out; + rsp_ctx.count = index; + rsp_ctx.dict = op_ctx; + dict_foreach (rsp_dict, _status_volume_add_brick_rsp, &rsp_ctx); + ret = dict_set_int32 (op_ctx, "count", count); - ret = glusterd_copy_folder (src_path, dest_path); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Could not copy " - "%s to %s", src_path, dest_path); - goto out; - } - } out: - if (origin_volname) - GF_ASSERT (origin_volname); - return ret; } -/* This is an utility function which will recursively delete - * a folder and its contents. - * - * @param delete_path folder to be deleted. - * - * @return 0 on success and -1 on failure. - */ int -glusterd_recursive_rmdir (const char *delete_path) +glusterd_defrag_volume_node_rsp (dict_t *req_dict, dict_t *rsp_dict, + dict_t *op_ctx) { - int ret = -1; - char path [PATH_MAX] = {0,}; - struct stat st = {0,}; - DIR *dir = NULL; - struct dirent *entry = NULL; - xlator_t *this = NULL; + int ret = 0; + char *volname = NULL; + glusterd_volinfo_t *volinfo = NULL; + char key[256] = {0,}; + int32_t i = 0; + char buf[1024] = {0,}; + char *node_str = NULL; + glusterd_conf_t *priv = NULL; - this = THIS; - GF_ASSERT (this); - GF_VALIDATE_OR_GOTO (this->name, delete_path, out); + priv = THIS->private; + GF_ASSERT (req_dict); - dir = opendir (delete_path); - if (!dir) { - gf_log (this->name, GF_LOG_DEBUG, "Failed to open directory %s." - " Reason : %s", delete_path, strerror (errno)); - ret = 0; + ret = dict_get_str (req_dict, "volname", &volname); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to get volume name"); goto out; } - glusterd_for_each_entry (entry, dir); - while (entry) { - snprintf (path, PATH_MAX, "%s/%s", delete_path, entry->d_name); - ret = lstat (path, &st); - if (ret == -1) { - gf_log (this->name, GF_LOG_DEBUG, "Failed to stat " - "entry %s : %s", path, strerror (errno)); - goto out; - } + ret = glusterd_volinfo_find (volname, &volinfo); - if (S_ISDIR (st.st_mode)) - ret = glusterd_recursive_rmdir (path); - else - ret = unlink (path); + if (ret) + goto out; + + if (rsp_dict) { + ret = glusterd_defrag_volume_status_update (volinfo, + rsp_dict); + } + + if (!op_ctx) { + dict_copy (rsp_dict, op_ctx); + goto out; + } + + ret = dict_get_int32 (op_ctx, "count", &i); + i++; + + ret = dict_set_int32 (op_ctx, "count", i); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, "Failed to set count"); + + snprintf (buf, 1024, "%s", uuid_utoa (MY_UUID)); + node_str = gf_strdup (buf); + + snprintf (key, 256, "node-uuid-%d",i); + ret = dict_set_dynstr (op_ctx, key, node_str); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set node-uuid"); + + memset (key, 0 , 256); + snprintf (key, 256, "files-%d", i); + ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.rebalance_files); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set file count"); + + memset (key, 0 , 256); + snprintf (key, 256, "size-%d", i); + ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.rebalance_data); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set size of xfer"); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, " Failed to remove " - "%s. Reason : %s", path, strerror (errno)); - } + memset (key, 0 , 256); + snprintf (key, 256, "lookups-%d", i); + ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.lookedup_files); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set lookedup file count"); - gf_log (this->name, GF_LOG_DEBUG, "%s %s", - ret ? "Failed to remove":"Removed", - entry->d_name); + memset (key, 0 , 256); + snprintf (key, 256, "status-%d", i); + ret = dict_set_int32 (op_ctx, key, volinfo->rebal.defrag_status); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set status"); - glusterd_for_each_entry (entry, dir); - } + memset (key, 0 , 256); + snprintf (key, 256, "failures-%d", i); + ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.rebalance_failures); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set failure count"); - ret = closedir (dir); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, "Failed to close dir %s. " - "Reason : %s", delete_path, strerror (errno)); - } + memset (key, 0 , 256); + snprintf (key, 256, "skipped-%d", i); + ret = dict_set_uint64 (op_ctx, key, volinfo->rebal.skipped_files); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set skipped count"); - ret = rmdir (delete_path); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, "Failed to rmdir: %s,err: %s", - delete_path, strerror (errno)); - } + memset (key, 0, 256); + snprintf (key, 256, "run-time-%d", i); + ret = dict_set_double (op_ctx, key, volinfo->rebal.rebalance_time); + if (ret) + gf_log (THIS->name, GF_LOG_ERROR, + "failed to set run-time"); out: return ret; } - -gf_boolean_t -glusterd_volume_quorum_calculate (glusterd_volinfo_t *volinfo, dict_t *dict, - int down_count, gf_boolean_t first_brick_on, - int8_t snap_force, int quorum_count, - char *quorum_type, char **op_errstr) +int32_t +glusterd_handle_node_rsp (dict_t *req_dict, void *pending_entry, + glusterd_op_t op, dict_t *rsp_dict, dict_t *op_ctx, + char **op_errstr, gd_node_type type) { - gf_boolean_t quorum_met = _gf_false; - char err_str[PATH_MAX] = {0, }; - xlator_t *this = NULL; - int up_count = 0; - - this = THIS; - GF_ASSERT (this); - - if (!volinfo || !dict) { - gf_log (this->name, GF_LOG_WARNING, "input parameters NULL"); - goto out; - } + int ret = 0; - if (!snap_force && down_count) { - snprintf (err_str, sizeof (err_str), "One or more bricks may " - "be down. Use the force option "); - gf_log (this->name, GF_LOG_ERROR, "%s", err_str); - *op_errstr = gf_strdup (err_str); - goto out; - } + GF_ASSERT (op_errstr); - up_count = volinfo->dist_leaf_count - down_count; + switch (op) { + case GD_OP_PROFILE_VOLUME: + ret = glusterd_profile_volume_brick_rsp (pending_entry, + rsp_dict, op_ctx, + op_errstr, type); + break; + case GD_OP_STATUS_VOLUME: + ret = glusterd_status_volume_brick_rsp (rsp_dict, op_ctx, + op_errstr); + break; - if (quorum_type && !strcmp (quorum_type, "fixed")) { - if (up_count >= quorum_count) { - quorum_met = _gf_true; - goto out; - } - } else { - if ((GF_CLUSTER_TYPE_DISPERSE != volinfo->type) && - (volinfo->dist_leaf_count % 2 == 0)) { - if ((up_count > quorum_count) || - ((up_count == quorum_count) && first_brick_on)) { - quorum_met = _gf_true; - goto out; - } - } else { - if (up_count >= quorum_count) { - quorum_met = _gf_true; - goto out; - } - } - } + case GD_OP_DEFRAG_BRICK_VOLUME: + glusterd_defrag_volume_node_rsp (req_dict, + rsp_dict, op_ctx); + break; - if (!quorum_met) { - snprintf (err_str, sizeof (err_str), "quorum is not met"); - gf_log (this->name, GF_LOG_WARNING, "%s", err_str); - *op_errstr = gf_strdup (err_str); + case GD_OP_HEAL_VOLUME: + ret = glusterd_heal_volume_brick_rsp (req_dict, rsp_dict, + op_ctx, op_errstr); + break; + default: + break; } -out: - return quorum_met; + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; } int32_t -glusterd_volume_quorum_check (glusterd_volinfo_t *volinfo, int64_t index, - dict_t *dict, char *key_prefix, - int8_t snap_force, int quorum_count, - char *quorum_type, char **op_errstr) -{ - int ret = 0; - xlator_t *this = NULL; - int64_t i = 0; - int64_t j = 0; - char key[1024] = {0, }; - int down_count = 0; - gf_boolean_t first_brick_on = _gf_true; - glusterd_conf_t *priv = NULL; - gf_boolean_t quorum_met = _gf_false; - int distribute_subvols = 0; - int32_t brick_online = 0; - char err_str[PATH_MAX] = {0, }; - - this = THIS; - GF_ASSERT (this); - priv = this->private; - GF_ASSERT (priv); - - if (!volinfo || !dict) { - gf_log (this->name, GF_LOG_WARNING, "input parameters NULL"); - goto out; - } - - if ((!glusterd_is_volume_replicate (volinfo) || - volinfo->replica_count < 3) && - (GF_CLUSTER_TYPE_DISPERSE != volinfo->type)) { - for (i = 0; i < volinfo->brick_count ; i++) { - /* for a pure distribute volume, and replica volume - with replica count 2, quorum is not met if even - one of its subvolumes is down - */ - snprintf (key, sizeof (key), "%s%"PRId64".brick%"PRId64".status", - key_prefix, index, i); - ret = dict_get_int32 (dict, key, &brick_online); - if (ret || !brick_online) { - ret = 1; - snprintf (err_str, sizeof (err_str), "quorum " - "is not met"); - gf_log (this->name, GF_LOG_ERROR, "%s", - err_str); - *op_errstr = gf_strdup (err_str); - goto out; - } - } - ret = 0; - quorum_met = _gf_true; - } else { - distribute_subvols = volinfo->brick_count / - volinfo->dist_leaf_count; - for (j = 0; j < distribute_subvols; j++) { - // by default assume quorum is not met - /* TODO: Handle distributed striped replicate volumes - Currently only distributed replicate volumes are - handled. - */ - ret = 1; - quorum_met = _gf_false; - for (i = 0; i < volinfo->dist_leaf_count; i++) { - snprintf (key, sizeof (key), - "%s%"PRId64".brick%"PRId64".status", key_prefix, - index, - (j * volinfo->dist_leaf_count) + i); - ret = dict_get_int32 (dict, key, &brick_online); - if (ret || !brick_online) { - if (i == 0) - first_brick_on = _gf_false; - down_count++; - } - } +glusterd_set_originator_uuid (dict_t *dict) +{ + int ret = -1; + uuid_t *originator_uuid = NULL; - quorum_met = glusterd_volume_quorum_calculate (volinfo, - dict, - down_count, - first_brick_on, - snap_force, - quorum_count, - quorum_type, - op_errstr); - // goto out if quorum is not met - if (!quorum_met) { - ret = -1; - goto out; - } + GF_ASSERT (dict); - down_count = 0; - first_brick_on = _gf_true; - } + originator_uuid = GF_CALLOC (1, sizeof(uuid_t), + gf_common_mt_uuid_t); + if (!originator_uuid) { + ret = -1; + goto out; } - if (quorum_met) { - gf_log (this->name, GF_LOG_DEBUG, "volume %s is in quorum", - volinfo->volname); - ret = 0; + uuid_copy (*originator_uuid, MY_UUID); + ret = dict_set_bin (dict, "originator_uuid", + originator_uuid, sizeof (uuid_t)); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Failed to set originator_uuid."); + goto out; } out: + if (ret && originator_uuid) + GF_FREE (originator_uuid); + return ret; } -int32_t -glusterd_snap_quorum_check_for_create (dict_t *dict, gf_boolean_t snap_volume, - char **op_errstr, - struct list_head *peers_list) -{ - int8_t snap_force = 0; - int32_t force = 0; - char err_str[PATH_MAX] = {0, }; - int quorum_count = 0; - char *quorum_type = NULL; - int32_t tmp = 0; - char key_prefix[PATH_MAX] = {0, }; - char *snapname = NULL; - glusterd_snap_t *snap = NULL; - glusterd_volinfo_t *volinfo = NULL; - char *volname = NULL; - int64_t volcount = 0; - char key[PATH_MAX] = {0, }; - int64_t i = 0; - int32_t ret = -1; - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); +/* Should be used only when an operation is in progress, as that is the only + * time a lock_owner is set + */ +gf_boolean_t +is_origin_glusterd (dict_t *dict) +{ + gf_boolean_t ret = _gf_false; + uuid_t lock_owner = {0,}; + uuid_t *originator_uuid = NULL; - if (!dict) { - gf_log (this->name, GF_LOG_ERROR, "dict is NULL"); - goto out; - } + GF_ASSERT (dict); - if (snap_volume) { - ret = dict_get_str (dict, "snapname", &snapname); + ret = dict_get_bin (dict, "originator_uuid", + (void **) &originator_uuid); + if (ret) { + /* If not originator_uuid has been set, then the command + * has been originated from a glusterd running on older version + * Hence fetching the lock owner */ + ret = glusterd_get_lock_owner (&lock_owner); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get snapname"); + ret = _gf_false; goto out; } + ret = !uuid_compare (MY_UUID, lock_owner); + } else + ret = !uuid_compare (MY_UUID, *originator_uuid); - snap = glusterd_find_snap_by_name (snapname); - if (!snap) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get the snapshot %s", snapname); - ret = -1; - goto out; - } - } +out: + return ret; +} - ret = dict_get_int32 (dict, "flags", &force); - if (!ret && (force & GF_CLI_FLAG_OP_FORCE)) - snap_force = 1; - if (!snap_force) { - /* Do a quorum check of glusterds also. Because, - the missed snapshot information will be saved - by glusterd and if glusterds are not in - quorum, then better fail the snapshot - */ - if (!does_gd_meet_server_quorum (this, peers_list, _gf_true)) { - snprintf (err_str, sizeof (err_str), - "glusterds are not in quorum"); - gf_log (this->name, GF_LOG_WARNING, "%s", - err_str); - *op_errstr = gf_strdup (err_str); - ret = -1; - goto out; - } +int +glusterd_generate_and_set_task_id (dict_t *dict, char *key) +{ + int ret = -1; + uuid_t task_id = {0,}; + char *uuid_str = NULL; + xlator_t *this = NULL; + + GF_ASSERT (dict); + + this = THIS; + GF_ASSERT (this); - gf_log (this->name, GF_LOG_DEBUG, "glusterds are in " - "quorum"); + uuid_generate (task_id); + uuid_str = gf_strdup (uuid_utoa (task_id)); + if (!uuid_str) { + ret = -1; + goto out; } - ret = dict_get_int64 (dict, "volcount", &volcount); + ret = dict_set_dynstr (dict, key, uuid_str); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to get " - "volcount"); + gf_log (this->name, GF_LOG_ERROR, "Failed to set %s in dict", + key); goto out; } + gf_log (this->name, GF_LOG_INFO, "Generated task-id %s for key %s", + uuid_str, key); - for (i = 1; i <= volcount; i++) { - snprintf (key, sizeof (key), "%s%"PRId64, - snap_volume?"snap-volname":"volname", i); - ret = dict_get_str (dict, key, &volname); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "failed to " - "get volname"); - goto out; - } - - if (snap_volume) { - ret = glusterd_snap_volinfo_find (volname, snap, - &volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to get snap volume %s " - "for snap %s", volname, - snapname); - goto out; - } - } else { - ret = glusterd_volinfo_find (volname, &volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "failed to find the volume %s", - volname); - goto out; - } - } - - /* for replicate volumes with replica count equal to or - greater than 3, do quorum check by getting what type - of quorum rule has been set by getting the volume - option set. If getting the option fails, then assume - default. - AFR does this: - if quorum type is "auto": - - for odd numner of bricks (n), n/2 + 1 - bricks should be present - - for even number of bricks n, n/2 bricks - should be present along with the 1st - subvolume - if quorum type is not "auto": - - get the quorum count from dict with the - help of the option "cluster.quorum-count" - if the option is not there in the dict, - then assume quorum type is auto and follow - the above method. - For non replicate volumes quorum is met only if all - the bricks of the volume are online - */ - - if (GF_CLUSTER_TYPE_REPLICATE == volinfo->type) { - if (volinfo->replica_count %2 == 0) - quorum_count = volinfo->replica_count/2; - else - quorum_count = - volinfo->replica_count/2 + 1; - } else if (GF_CLUSTER_TYPE_DISPERSE == volinfo->type) { - quorum_count = volinfo->disperse_count - - volinfo->redundancy_count; - } else { - quorum_count = volinfo->brick_count; - } - - ret = dict_get_str (volinfo->dict, - "cluster.quorum-type", - &quorum_type); - if (!ret && !strcmp (quorum_type, "fixed")) { - ret = dict_get_int32 (volinfo->dict, - "cluster.quorum-count", - &tmp); - /* if quorum-type option is not found in the - dict assume auto quorum type. i.e n/2 + 1. - The same assumption is made when quorum-count - option cannot be obtained from the dict (even - if the quorum-type option is not set to auto, - the behavior is set to the default behavior) - */ - if (!ret) { - /* for dispersed volumes, only allow quorums - equal or larger than minimum functional - value. - */ - if ((GF_CLUSTER_TYPE_DISPERSE != - volinfo->type) || - (tmp >= quorum_count)) { - quorum_count = tmp; - } else { - gf_log(this->name, GF_LOG_INFO, - "Ignoring small quorum-count " - "(%d) on dispersed volume", tmp); - quorum_type = NULL; - } - } - else - quorum_type = NULL; - } - - snprintf (key_prefix, sizeof (key_prefix), - "%s", snap_volume?"snap-vol":"vol"); - - ret = glusterd_volume_quorum_check (volinfo, i, dict, - key_prefix, - snap_force, - quorum_count, - quorum_type, - op_errstr); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "volume %s " - "is not in quorum", volinfo->volname); - goto out; - } - } out: + if (ret) + GF_FREE (uuid_str); return ret; } -int32_t -glusterd_snap_quorum_check (dict_t *dict, gf_boolean_t snap_volume, - char **op_errstr, - struct list_head *peers_list) +int +glusterd_copy_uuid_to_dict (uuid_t uuid, dict_t *dict, char *key) { - int32_t ret = -1; - xlator_t *this = NULL; - int32_t snap_command = 0; - char err_str[PATH_MAX] = {0, }; + int ret = -1; + char tmp_str[40] = {0,}; + char *task_id_str = NULL; - this = THIS; - GF_ASSERT (this); + GF_ASSERT (dict); + GF_ASSERT (key); - if (!dict) { - gf_log (this->name, GF_LOG_ERROR, "dict is NULL"); - goto out; + uuid_unparse (uuid, tmp_str); + task_id_str = gf_strdup (tmp_str); + if (!task_id_str) + return -1; + + ret = dict_set_dynstr (dict, key, task_id_str); + if (ret) { + GF_FREE (task_id_str); + gf_log (THIS->name, GF_LOG_ERROR, + "Error setting uuid in dict with key %s", key); } + return 0; +} + +int +_update_volume_op_versions (dict_t *this, char *key, data_t *value, void *data) +{ + int op_version = 0; + glusterd_volinfo_t *ctx = NULL; + gf_boolean_t enabled = _gf_true; + int ret = -1; + + GF_ASSERT (data); + ctx = data; - ret = dict_get_int32 (dict, "type", &snap_command); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "unable to get the type of " - "the snapshot command"); - goto out; - } + op_version = glusterd_get_op_version_for_key (key); - switch (snap_command) { - case GF_SNAP_OPTION_TYPE_CREATE: - ret = glusterd_snap_quorum_check_for_create (dict, snap_volume, - op_errstr, - peers_list); - if (ret) { - gf_log (this->name, GF_LOG_WARNING, "Quorum check" - "failed during snapshot create command"); - goto out; - } - break; - case GF_SNAP_OPTION_TYPE_DELETE: - case GF_SNAP_OPTION_TYPE_RESTORE: - if (!does_gd_meet_server_quorum (this, peers_list, _gf_true)) { - ret = -1; - snprintf (err_str, sizeof (err_str), - "glusterds are not in quorum"); - gf_log (this->name, GF_LOG_WARNING, "%s", - err_str); - *op_errstr = gf_strdup (err_str); - goto out; - } + if (gd_is_xlator_option (key) || gd_is_boolean_option (key)) { + ret = gf_string2boolean (value->data, &enabled); + if (ret) + return 0; - gf_log (this->name, GF_LOG_DEBUG, "glusterds are in " - "quorum"); - break; - default: - break; + if (!enabled) + return 0; } - ret = 0; + if (op_version > ctx->op_version) + ctx->op_version = op_version; -out: - return ret; -} + if (gd_is_client_option (key) && + (op_version > ctx->client_op_version)) + ctx->client_op_version = op_version; -static int -gd_default_synctask_cbk (int ret, call_frame_t *frame, void *opaque) -{ - glusterd_conf_t *priv = THIS->private; - synclock_unlock (&priv->big_lock); - return ret; + return 0; } void -glusterd_launch_synctask (synctask_fn_t fn, void *opaque) +gd_update_volume_op_versions (glusterd_volinfo_t *volinfo) { - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - int ret = -1; + glusterd_conf_t *conf = NULL; + gf_boolean_t ob_enabled = _gf_false; - this = THIS; - priv = this->private; + GF_ASSERT (volinfo); - synclock_lock (&priv->big_lock); - ret = synctask_new (this->ctx->env, fn, gd_default_synctask_cbk, NULL, - opaque); - if (ret) - gf_log (this->name, GF_LOG_CRITICAL, "Failed to spawn bricks" - " and other volume related services"); -} + conf = THIS->private; + GF_ASSERT (conf); -/* - * glusterd_enable_default_options enable certain options by default on the - * given volume based on the cluster op-version. This is called only during - * volume create or during volume reset - * - * @volinfo - volume on which to enable the default options - * @option - option to be set to default. If NULL, all possible options will be - * set to default - * - * Returns 0 on sucess and -1 on failure. If @option is given, but doesn't match - * any of the options that could be set, it is a success. - */ -/* - * TODO: Make this able to parse the volume-set table to set options - * Currently, the check and set for any option which wants to make use of this - * 'framework' needs to be done here manually. This would mean more work for the - * developer. This little extra work can be avoided if we make it possible to - * parse the volume-set table to get the options which could be set and their - * default values - */ -int -glusterd_enable_default_options (glusterd_volinfo_t *volinfo, char *option) -{ - int ret = 0; - xlator_t *this = NULL; - glusterd_conf_t *conf = NULL; + /* Reset op-versions to minimum */ + volinfo->op_version = 1; + volinfo->client_op_version = 1; - this = THIS; - GF_ASSERT (this); + dict_foreach (volinfo->dict, _update_volume_op_versions, volinfo); - GF_VALIDATE_OR_GOTO (this->name, volinfo, out); + /* Special case for open-behind + * If cluster op-version >= 2 and open-behind hasn't been explicitly + * disabled, volume op-versions must be updated to account for it + */ - conf = this->private; - GF_ASSERT (conf); + /* TODO: Remove once we have a general way to update automatically + * enabled features + */ + if (conf->op_version >= 2) { + ob_enabled = dict_get_str_boolean (volinfo->dict, + "performance.open-behind", + _gf_true); + if (ob_enabled) { - if (conf->op_version >= GD_OP_VERSION_3_6_0) { - /* Set needed volume options in volinfo->dict - * For ex., - * - * if (!option || !strcmp("someoption", option) { - * ret = dict_set_str(volinfo->dict, "someoption", "on"); - * ... - * } - * */ + if (volinfo->op_version < 2) + volinfo->op_version = 2; + if (volinfo->client_op_version < 2) + volinfo->client_op_version = 2; + } } -out: - return ret; + + if (volinfo->type == GF_CLUSTER_TYPE_DISPERSE) { + if (volinfo->op_version < GD_OP_VERSION_3_6_0) + volinfo->op_version = GD_OP_VERSION_3_6_0; + if (volinfo->client_op_version < GD_OP_VERSION_3_6_0) + volinfo->client_op_version = GD_OP_VERSION_3_6_0; + } + + return; } -void -glusterd_get_rebalance_volfile (glusterd_volinfo_t *volinfo, - char *path, int path_len) +int +op_version_check (xlator_t *this, int min_op_version, char *msg, int msglen) { - char workdir[PATH_MAX] = {0,}; - glusterd_conf_t *priv = THIS->private; + int ret = 0; + glusterd_conf_t *priv = NULL; - GLUSTERD_GET_VOLUME_DIR (workdir, volinfo, priv); + GF_ASSERT (this); + GF_ASSERT (msg); - snprintf (path, path_len, "%s/%s-rebalance.vol", workdir, - volinfo->volname); + priv = this->private; + if (priv->op_version < min_op_version) { + snprintf (msg, msglen, "One or more nodes do not support " + "the required op-version. Cluster op-version must " + "atleast be %d.", min_op_version); + gf_log (this->name, GF_LOG_ERROR, "%s", msg); + ret = -1; + } + return ret; } -/* Snapd functions */ -int -glusterd_is_snapd_enabled (glusterd_volinfo_t *volinfo) -{ - int ret = 0; - xlator_t *this = THIS; - ret = dict_get_str_boolean (volinfo->dict, "features.uss", -2); - if (ret == -2) { - gf_log (this->name, GF_LOG_DEBUG, "Key features.uss not " - "present in the dict for volume %s", volinfo->volname); - ret = 0; +/* A task is committed/completed once the task-id for it is cleared */ +gf_boolean_t +gd_is_remove_brick_committed (glusterd_volinfo_t *volinfo) +{ + GF_ASSERT (volinfo); - } else if (ret == -1) { - gf_log (this->name, GF_LOG_ERROR, "Failed to get 'features.uss'" - " from dict for volume %s", volinfo->volname); - } + if ((GD_OP_REMOVE_BRICK == volinfo->rebal.op) && + !uuid_is_null (volinfo->rebal.rebalance_id)) + return _gf_false; - return ret; + return _gf_true; } -void -glusterd_get_snapd_rundir (glusterd_volinfo_t *volinfo, - char *path, int path_len) +gf_boolean_t +glusterd_is_status_tasks_op (glusterd_op_t op, dict_t *dict) { - char workdir [PATH_MAX] = {0,}; - glusterd_conf_t *priv = THIS->private; + int ret = -1; + uint32_t cmd = GF_CLI_STATUS_NONE; + gf_boolean_t is_status_tasks = _gf_false; - GLUSTERD_GET_VOLUME_DIR (workdir, volinfo, priv); + if (op != GD_OP_STATUS_VOLUME) + goto out; + + ret = dict_get_uint32 (dict, "cmd", &cmd); + if (ret) { + gf_log (THIS->name, GF_LOG_ERROR, "Failed to get opcode"); + goto out; + } + + if (cmd & GF_CLI_STATUS_TASKS) + is_status_tasks = _gf_true; - snprintf (path, path_len, "%s/run", workdir); +out: + return is_status_tasks; } -void -glusterd_get_snapd_volfile (glusterd_volinfo_t *volinfo, - char *path, int path_len) -{ - char workdir [PATH_MAX] = {0,}; - glusterd_conf_t *priv = THIS->private; +/* Tells if rebalance needs to be started for the given volume on the peer + * + * Rebalance should be started on a peer only if an involved brick is present on + * the peer. + * + * For a normal rebalance, if any one brick of the given volume is present on + * the peer, the rebalance process should be started. + * + * For a rebalance as part of a remove-brick operation, the rebalance process + * should be started only if one of the bricks being removed is present on the + * peer + */ +gf_boolean_t +gd_should_i_start_rebalance (glusterd_volinfo_t *volinfo) { + gf_boolean_t retval = _gf_false; + int ret = -1; + glusterd_brickinfo_t *brick = NULL; + int count = 0; + int i = 0; + char key[1023] = {0,}; + char *brickname = NULL; - GLUSTERD_GET_VOLUME_DIR (workdir, volinfo, priv); - snprintf (path, path_len, "%s/%s-snapd.vol", workdir, - volinfo->volname); + switch (volinfo->rebal.op) { + case GD_OP_REBALANCE: + list_for_each_entry (brick, &volinfo->bricks, brick_list) { + if (uuid_compare (MY_UUID, brick->uuid) == 0) { + retval = _gf_true; + break; + } + } + break; + case GD_OP_REMOVE_BRICK: + ret = dict_get_int32 (volinfo->rebal.dict, "count", &count); + if (ret) { + goto out; + } + for (i = 1; i <= count; i++) { + memset (key, 0, sizeof (key)); + snprintf (key, sizeof (key), "brick%d", i); + ret = dict_get_str (volinfo->rebal.dict, key, + &brickname); + if (ret) + goto out; + ret = glusterd_volume_brickinfo_get_by_brick (brickname, + volinfo, + &brick); + if (ret) + goto out; + if (uuid_compare (MY_UUID, brick->uuid) == 0) { + retval = _gf_true; + break; + } + } + break; + default: + break; + } + +out: + return retval; } -void -glusterd_get_snapd_pidfile (glusterd_volinfo_t *volinfo, - char *path, int path_len) +int +glusterd_is_volume_quota_enabled (glusterd_volinfo_t *volinfo) { - char rundir [PATH_MAX] = {0,}; - - glusterd_get_snapd_rundir (volinfo, rundir, sizeof (rundir)); - - snprintf (path, path_len, "%s/%s-snapd.pid", rundir, volinfo->volname); + return (glusterd_volinfo_get_boolean (volinfo, VKEY_FEATURES_QUOTA)); } -void -glusterd_set_snapd_socket_filepath (glusterd_volinfo_t *volinfo, - char *path, int path_len) +int +glusterd_validate_and_set_gfid (dict_t *op_ctx, dict_t *req_dict, + char **op_errstr) { - char sockfilepath[PATH_MAX] = {0,}; - char rundir[PATH_MAX] = {0,}; + int ret = -1; + int count = 0; + int i = 0; + int op_code = GF_QUOTA_OPTION_TYPE_NONE; + uuid_t uuid1 = {0}; + uuid_t uuid2 = {0,}; + char *path = NULL; + char key[256] = {0,}; + char *uuid1_str = NULL; + char *uuid1_str_dup = NULL; + char *uuid2_str = NULL; + xlator_t *this = NULL; - glusterd_get_snapd_rundir (volinfo, rundir, sizeof (rundir)); - snprintf (sockfilepath, sizeof (sockfilepath), "%s/run-%s", - rundir, uuid_utoa (MY_UUID)); + this = THIS; + GF_ASSERT (this); - glusterd_set_socket_filepath (sockfilepath, path, path_len); -} + ret = dict_get_int32 (op_ctx, "type", &op_code); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get quota opcode"); + goto out; + } -gf_boolean_t -glusterd_is_snapd_running (glusterd_volinfo_t *volinfo) -{ - char pidfile [PATH_MAX] = {0,}; - int pid = -1; - glusterd_conf_t *priv = THIS->private; + if ((op_code != GF_QUOTA_OPTION_TYPE_LIMIT_USAGE) && + (op_code != GF_QUOTA_OPTION_TYPE_REMOVE)) { + ret = 0; + goto out; + } - glusterd_get_snapd_pidfile (volinfo, pidfile, - sizeof (pidfile)); + ret = dict_get_str (op_ctx, "path", &path); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get path"); + goto out; + } - return gf_is_service_running (pidfile, &pid); -} + ret = dict_get_int32 (op_ctx, "count", &count); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get count"); + goto out; + } -int -glusterd_restart_snapds (glusterd_conf_t *priv) -{ - glusterd_volinfo_t *volinfo = NULL; - int ret = 0; - xlator_t *this = THIS; + /* If count is 0, fail the command with ENOENT. + * + * If count is 1, treat gfid0 as the gfid on which the operation + * is to be performed and resume the command. + * + * if count > 1, get the 0th gfid from the op_ctx and, + * compare it with the remaining 'count -1' gfids. + * If they are found to be the same, set gfid0 in the op_ctx and + * resume the operation, else error out. + */ - list_for_each_entry (volinfo, &priv->volumes, vol_list) { - if (volinfo->status == GLUSTERD_STATUS_STARTED && - glusterd_is_snapd_enabled (volinfo)) { - ret = glusterd_snapd_start (volinfo, - _gf_false); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Couldn't start snapd for " - "vol: %s", volinfo->volname); - goto out; - } - } + if (count == 0) { + gf_asprintf (op_errstr, "Failed to get trusted.gfid attribute " + "on path %s. Reason : %s", path, + strerror (ENOENT)); + ret = -1; + goto out; } -out: - return ret; -} - -gf_boolean_t -glusterd_is_snapd_online (glusterd_volinfo_t *volinfo) -{ - return volinfo->snapd.online; -} -void -glusterd_snapd_set_online_status (glusterd_volinfo_t *volinfo, - gf_boolean_t status) -{ - volinfo->snapd.online = status; -} + snprintf (key, sizeof (key) - 1, "gfid%d", 0); -static inline void -glusterd_snapd_set_rpc (glusterd_volinfo_t *volinfo, struct rpc_clnt *rpc) -{ - volinfo->snapd.rpc = rpc; -} + ret = dict_get_str (op_ctx, key, &uuid1_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get key '%s'", + key); + goto out; + } -int32_t -glusterd_snapd_connect (glusterd_volinfo_t *volinfo, char *socketpath) -{ - int ret = 0; - dict_t *options = NULL; - struct rpc_clnt *rpc = NULL; - glusterd_conf_t *priv = THIS->private; + uuid_parse (uuid1_str, uuid1); - rpc = glusterd_snapd_get_rpc (volinfo); + for (i = 1; i < count; i++) { + snprintf (key, sizeof (key)-1, "gfid%d", i); - if (rpc == NULL) { - /* Setting frame-timeout to 10mins (600seconds). - * Unix domain sockets ensures that the connection is reliable. - * The default timeout of 30mins used for unreliable network - * connections is too long for unix domain socket connections. - */ - ret = rpc_transport_unix_options_build (&options, socketpath, - 600); - if (ret) + ret = dict_get_str (op_ctx, key, &uuid2_str); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to get key " + "'%s'", key); goto out; + } - ret = dict_set_str(options, - "transport.socket.ignore-enoent", "on"); - if (ret) - goto out; + uuid_parse (uuid2_str, uuid2); - glusterd_volinfo_ref (volinfo); + if (uuid_compare (uuid1, uuid2)) { + gf_asprintf (op_errstr, "gfid mismatch between %s and " + "%s for path %s", uuid1_str, uuid2_str, + path); + ret = -1; + goto out; + } + } - synclock_unlock (&priv->big_lock); - ret = glusterd_rpc_create (&rpc, options, - glusterd_snapd_rpc_notify, - volinfo); - synclock_lock (&priv->big_lock); - if (ret) + if (i == count) { + uuid1_str_dup = gf_strdup (uuid1_str); + if (!uuid1_str_dup) { + ret = -1; goto out; + } - (void) glusterd_snapd_set_rpc (volinfo, rpc); + ret = dict_set_dynstr (req_dict, "gfid", uuid1_str_dup); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to set gfid"); + GF_FREE (uuid1_str_dup); + goto out; + } + } else { + gf_log (this->name, GF_LOG_ERROR, "Failed to iterate through %d" + " entries in the req dict", count); + ret = -1; + goto out; } + + ret = 0; out: return ret; } -int32_t -glusterd_snapd_disconnect (glusterd_volinfo_t *volinfo) +void +glusterd_clean_up_quota_store (glusterd_volinfo_t *volinfo) { - struct rpc_clnt *rpc = NULL; - glusterd_conf_t *priv = THIS->private; - - rpc = glusterd_snapd_get_rpc (volinfo); + char voldir[PATH_MAX] = {0,}; + char quota_confpath[PATH_MAX] = {0,}; + char cksum_path[PATH_MAX] = {0,}; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; - (void) glusterd_snapd_set_rpc (volinfo, NULL); + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); - if (rpc) - glusterd_rpc_clnt_unref (priv, rpc); + GLUSTERD_GET_VOLUME_DIR (voldir, volinfo, conf); - return 0; -} + snprintf (quota_confpath, sizeof (quota_confpath), "%s/%s", voldir, + GLUSTERD_VOLUME_QUOTA_CONFIG); + snprintf (cksum_path, sizeof (cksum_path), "%s/%s", voldir, + GLUSTERD_VOL_QUOTA_CKSUM_FILE); -int32_t -glusterd_snapd_start (glusterd_volinfo_t *volinfo, gf_boolean_t wait) -{ - int32_t ret = -1; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; - runner_t runner = {0,}; - char pidfile[PATH_MAX] = {0,}; - char logfile[PATH_MAX] = {0,}; - char logdir[PATH_MAX] = {0,}; - char volfile[PATH_MAX] = {0,}; - char glusterd_uuid [1024] = {0,}; - char rundir[PATH_MAX] = {0,}; - char sockfpath[PATH_MAX] = {0,}; - char volfileid[256] = {0}; - char *volfileserver = NULL; - char valgrind_logfile[PATH_MAX] = {0}; - int snapd_port = 0; - char *volname = volinfo->volname; - char snapd_id [PATH_MAX] = {0,}; - char msg [1024] = {0,}; + unlink (quota_confpath); + unlink (cksum_path); - this = THIS; - GF_ASSERT(this); + gf_store_handle_destroy (volinfo->quota_conf_shandle); + volinfo->quota_conf_shandle = NULL; + volinfo->quota_conf_version = 0; - if (glusterd_is_snapd_running (volinfo)) { - ret = 0; - goto connect; - } +} - priv = this->private; +#define QUOTA_CONF_HEADER \ + "GlusterFS Quota conf | version: v%d.%d\n" - glusterd_get_snapd_rundir (volinfo, rundir, sizeof (rundir)); - ret = mkdir (rundir, 0777); +int +glusterd_store_quota_conf_skip_header (xlator_t *this, int fd) +{ + char buf[PATH_MAX] = {0,}; - if ((ret == -1) && (EEXIST != errno)) { - gf_log (this->name, GF_LOG_ERROR, "Unable to create rundir %s", - rundir); - goto out; - } + snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); + return gf_skip_header_section (fd, strlen (buf)); +} - glusterd_get_snapd_pidfile (volinfo, pidfile, sizeof (pidfile)); - glusterd_get_snapd_volfile (volinfo, volfile, sizeof (volfile)); +int +glusterd_store_quota_conf_stamp_header (xlator_t *this, int fd) +{ + char buf[PATH_MAX] = {0,}; + int buf_len = 0; + ssize_t ret = -1; + ssize_t written = 0; - ret = sys_access (volfile, F_OK); - if (ret) { - gf_log (this->name, GF_LOG_DEBUG, - "snapd Volfile %s is not present", volfile); - - /* If glusterd is down on one of the nodes and during - * that time "USS is enabled" for the first time. After some - * time when the glusterd which was down comes back it tries - * to look for the snapd volfile and it does not find snapd - * volfile and because of this starting of snapd fails. - * Therefore, if volfile is not present then create a fresh - * volfile. - */ - ret = glusterd_create_snapd_volfile (volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Couldn't create " - "snapd volfile for volume: %s", - volinfo->volname); + snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1); + buf_len = strlen (buf); + for (written = 0; written != buf_len; written += ret) { + ret = write (fd, buf + written, buf_len - written); + if (ret == -1) { goto out; } } - snprintf (logdir, PATH_MAX, "%s/snaps/%s", - DEFAULT_LOG_FILE_DIRECTORY, volname); - ret = mkdir_p (logdir, 0755, _gf_true); - if ((ret == -1) && (EEXIST != errno)) { - gf_log (this->name, GF_LOG_ERROR, "Unable to create logdir %s", - logdir); - goto out; - } - - snprintf (logfile, PATH_MAX, "%s/snapd.log", logdir); - - snprintf (volfileid, sizeof (volfileid), "snapd/%s", volname); - glusterd_set_snapd_socket_filepath (volinfo, sockfpath, - sizeof (sockfpath)); - - if (dict_get_str (this->options, "transport.socket.bind-address", - &volfileserver) != 0) { - volfileserver = "localhost"; - } - - runinit (&runner); - - if (priv->valgrind) { - snprintf (valgrind_logfile, PATH_MAX, "%s/valgrind-snapd.log", - logdir); + ret = 0; +out: + return ret; +} - runner_add_args (&runner, "valgrind", "--leak-check=full", - "--trace-children=yes", "--track-origins=yes", - NULL); - runner_argprintf (&runner, "--log-file=%s", valgrind_logfile); - } +int +glusterd_remove_auxiliary_mount (char *volname) +{ + int ret = -1; + char mountdir[PATH_MAX] = {0,}; + char pidfile[PATH_MAX] = {0,}; + xlator_t *this = NULL; - snprintf (snapd_id, sizeof (snapd_id), "snapd-%s", volname); - runner_add_args (&runner, SBIN_DIR"/glusterfsd", - "-s", volfileserver, - "--volfile-id", volfileid, - "-p", pidfile, - "-l", logfile, - "--brick-name", snapd_id, - "-S", sockfpath, NULL); + this = THIS; + GF_ASSERT (this); - snapd_port = volinfo->snapd.port; - if (!snapd_port) { - snapd_port = pmap_registry_alloc (THIS); - if (!snapd_port) { - snprintf (msg, sizeof (msg), "Could not allocate port " - "for snapd service for volume %s", volname); + GLUSTERFS_GET_AUX_MOUNT_PIDFILE (pidfile, volname); - runner_log (&runner, this->name, GF_LOG_DEBUG, msg); - ret = -1; - goto out; - } + if (!gf_is_service_running (pidfile, NULL)) { + gf_log (this->name, GF_LOG_DEBUG, "Aux mount of volume %s " + "absent, hence returning", volname); + return 0; } - runner_add_arg (&runner, "--brick-port"); - runner_argprintf (&runner, "%d", snapd_port); - runner_add_arg (&runner, "--xlator-option"); - runner_argprintf (&runner, "%s-server.listen-port=%d", - volname, snapd_port); + GLUSTERD_GET_QUOTA_AUX_MOUNT_PATH (mountdir, volname, "/"); + ret = gf_umount_lazy (this->name, mountdir, 1); + if (ret) + gf_log (this->name, GF_LOG_ERROR, "umount on %s failed, " + "reason : %s", mountdir, strerror (errno)); - snprintf (msg, sizeof (msg), - "Starting the snapd service for volume %s", volname); - runner_log (&runner, this->name, GF_LOG_DEBUG, msg); + return ret; +} - if (!wait) { - ret = runner_run_nowait (&runner); - } else { - synclock_unlock (&priv->big_lock); - { - ret = runner_run (&runner); - } - synclock_lock (&priv->big_lock); - } +/* Stops the rebalance process of the given volume + */ +int +gd_stop_rebalance_process (glusterd_volinfo_t *volinfo) +{ + int ret = -1; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + char pidfile[PATH_MAX] = {0,}; - volinfo->snapd.port = snapd_port; + GF_ASSERT (volinfo); -connect: - if (ret == 0) - glusterd_snapd_connect (volinfo, sockfpath); + this = THIS; + GF_ASSERT (this); + + conf = this->private; + GF_ASSERT (conf); + + GLUSTERD_GET_DEFRAG_PID_FILE (pidfile, volinfo, conf); + ret = glusterd_service_stop ("rebalance", pidfile, SIGTERM, _gf_true); -out: return ret; } -int -glusterd_snapd_stop (glusterd_volinfo_t *volinfo) +rpc_clnt_t * +glusterd_rpc_clnt_unref (glusterd_conf_t *conf, rpc_clnt_t *rpc) { - char pidfile [PATH_MAX] = {0,}; - char sockfpath [PATH_MAX] = {0,}; - glusterd_conf_t *priv = THIS->private; - int ret = 0; + rpc_clnt_t *ret = NULL; - (void)glusterd_snapd_disconnect (volinfo); + GF_ASSERT (conf); + GF_ASSERT (rpc); + synclock_unlock (&conf->big_lock); + ret = rpc_clnt_unref (rpc); + synclock_lock (&conf->big_lock); - if (!glusterd_is_snapd_running (volinfo)) - goto out; + return ret; +} - glusterd_get_snapd_pidfile (volinfo, pidfile, sizeof (pidfile)); - ret = glusterd_service_stop ("snapd", pidfile, SIGTERM, _gf_true); +int32_t +glusterd_compare_volume_name(struct list_head *list1, struct list_head *list2) +{ + glusterd_volinfo_t *volinfo1 = NULL; + glusterd_volinfo_t *volinfo2 = NULL; - if (ret == 0) { - glusterd_set_snapd_socket_filepath (volinfo, sockfpath, - sizeof (sockfpath)); - (void)glusterd_unlink_file (sockfpath); - } -out: - return ret; + volinfo1 = list_entry(list1, glusterd_volinfo_t, vol_list); + volinfo2 = list_entry(list2, glusterd_volinfo_t, vol_list); + return strcmp(volinfo1->volname, volinfo2->volname); } +/* This is an utility function which will recursively delete + * a folder and its contents. + * + * @param delete_path folder to be deleted. + * + * @return 0 on success and -1 on failure. + */ int -glusterd_handle_snapd_option (glusterd_volinfo_t *volinfo) +glusterd_recursive_rmdir (const char *delete_path) { - int ret = 0; - xlator_t *this = THIS; + int ret = -1; + char path [PATH_MAX] = {0,}; + struct stat st = {0,}; + DIR *dir = NULL; + struct dirent *entry = NULL; + xlator_t *this = NULL; - if (volinfo->is_snap_volume) - return 0; + this = THIS; + GF_ASSERT (this); + GF_VALIDATE_OR_GOTO (this->name, delete_path, out); - ret = glusterd_is_snapd_enabled (volinfo); - if (ret == -1) { - gf_log (this->name, GF_LOG_ERROR, "Failed to read volume " - "options"); + dir = opendir (delete_path); + if (!dir) { + gf_log (this->name, GF_LOG_DEBUG, "Failed to open directory %s." + " Reason : %s", delete_path, strerror (errno)); + ret = 0; goto out; } - if (ret) { - if (!glusterd_is_volume_started (volinfo)) { - if (glusterd_is_snapd_running (volinfo)) { - ret = glusterd_snapd_stop (volinfo); - if (ret) - gf_log (this->name, GF_LOG_ERROR, - "Couldn't stop snapd for " - "volume: %s", - volinfo->volname); - } else { - /* Since snapd is not running set ret to 0 */ - ret = 0; - } + glusterd_for_each_entry (entry, dir); + while (entry) { + snprintf (path, PATH_MAX, "%s/%s", delete_path, entry->d_name); + ret = lstat (path, &st); + if (ret == -1) { + gf_log (this->name, GF_LOG_DEBUG, "Failed to stat " + "entry %s : %s", path, strerror (errno)); goto out; } - ret = glusterd_create_snapd_volfile (volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Couldn't create " - "snapd volfile for volume: %s", - volinfo->volname); - goto out; - } + if (S_ISDIR (st.st_mode)) + ret = glusterd_recursive_rmdir (path); + else + ret = unlink (path); - ret = glusterd_snapd_start (volinfo, _gf_false); if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Couldn't start " - "snapd for volume: %s", volinfo->volname); - goto out; + gf_log (this->name, GF_LOG_DEBUG, " Failed to remove " + "%s. Reason : %s", path, strerror (errno)); } - } else if (glusterd_is_snapd_running (volinfo)) { - ret = glusterd_snapd_stop (volinfo); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, - "Couldn't stop snapd for volume: %s", - volinfo->volname); - goto out; - } - volinfo->snapd.port = 0; + gf_log (this->name, GF_LOG_DEBUG, "%s %s", + ret ? "Failed to remove":"Removed", + entry->d_name); + + glusterd_for_each_entry (entry, dir); + } + + ret = closedir (dir); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "Failed to close dir %s. " + "Reason : %s", delete_path, strerror (errno)); + } + + ret = rmdir (delete_path); + if (ret) { + gf_log (this->name, GF_LOG_DEBUG, "Failed to rmdir: %s,err: %s", + delete_path, strerror (errno)); } out: return ret; } -int32_t -glusterd_is_snap_soft_limit_reached (glusterd_volinfo_t *volinfo, dict_t *dict) +static int +gd_default_synctask_cbk (int ret, call_frame_t *frame, void *opaque) { - int32_t ret = -1; - uint64_t opt_max_hard = GLUSTERD_SNAPS_MAX_HARD_LIMIT; - uint64_t opt_max_soft = GLUSTERD_SNAPS_DEF_SOFT_LIMIT_PERCENT; - uint64_t limit = 0; - int auto_delete = 0; - uint64_t effective_max_limit = 0; - xlator_t *this = NULL; - glusterd_conf_t *priv = NULL; + glusterd_conf_t *priv = THIS->private; + synclock_unlock (&priv->big_lock); + return ret; +} - GF_ASSERT (volinfo); - GF_ASSERT (dict); +void +glusterd_launch_synctask (synctask_fn_t fn, void *opaque) +{ + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + int ret = -1; this = THIS; - GF_ASSERT (this); priv = this->private; - GF_ASSERT (priv); - /* config values snap-max-hard-limit and snap-max-soft-limit are - * optional and hence we are not erroring out if values are not - * present - */ - gd_get_snap_conf_values_if_present (priv->opts, &opt_max_hard, - &opt_max_soft); + synclock_lock (&priv->big_lock); + ret = synctask_new (this->ctx->env, fn, gd_default_synctask_cbk, NULL, + opaque); + if (ret) + gf_log (this->name, GF_LOG_CRITICAL, "Failed to spawn bricks" + " and other volume related services"); +} - /* "auto-delete" might not be set by user explicitly, - * in that case it's better to consider the default value. - * Hence not erroring out if Key is not found. - */ - auto_delete = dict_get_str_boolean (priv->opts, - GLUSTERD_STORE_KEY_SNAP_AUTO_DELETE, - _gf_false); +/* + * glusterd_enable_default_options enable certain options by default on the + * given volume based on the cluster op-version. This is called only during + * volume create or during volume reset + * + * @volinfo - volume on which to enable the default options + * @option - option to be set to default. If NULL, all possible options will be + * set to default + * + * Returns 0 on sucess and -1 on failure. If @option is given, but doesn't match + * any of the options that could be set, it is a success. + */ +/* + * TODO: Make this able to parse the volume-set table to set options + * Currently, the check and set for any option which wants to make use of this + * 'framework' needs to be done here manually. This would mean more work for the + * developer. This little extra work can be avoided if we make it possible to + * parse the volume-set table to get the options which could be set and their + * default values + */ +int +glusterd_enable_default_options (glusterd_volinfo_t *volinfo, char *option) +{ + int ret = 0; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; - if (volinfo->snap_max_hard_limit < opt_max_hard) - effective_max_limit = volinfo->snap_max_hard_limit; - else - effective_max_limit = opt_max_hard; + this = THIS; + GF_ASSERT (this); - limit = (opt_max_soft * effective_max_limit)/100; + GF_VALIDATE_OR_GOTO (this->name, volinfo, out); - if (volinfo->snap_count >= limit && auto_delete != _gf_true) { - gf_log (this->name, GF_LOG_WARNING, "Soft-limit " - "(value = %"PRIu64") of volume %s is reached. " - "Snapshot creation is not possible once effective " - "hard-limit (value = %"PRIu64") is reached.", - limit, volinfo->volname, effective_max_limit); + conf = this->private; + GF_ASSERT (conf); - ret = dict_set_int8 (dict, "soft-limit-reach", - _gf_true); - if (ret) { - gf_log (this->name, GF_LOG_ERROR, "Failed to " - "set soft limit exceed flag in " - "response dictionary"); - } - goto out; + if (conf->op_version >= GD_OP_VERSION_3_6_0) { + /* Set needed volume options in volinfo->dict + * For ex., + * + * if (!option || !strcmp("someoption", option) { + * ret = dict_set_str(volinfo->dict, "someoption", "on"); + * ... + * } + * */ } - ret = 0; -out : +out: return ret; } -/* This function initializes the parameter sys_hard_limit, - * sys_soft_limit and auto_delete value to the value set - * in dictionary, If value is not present then it is - * initialized to default values. Hence this function does not - * return any values. - */ void -gd_get_snap_conf_values_if_present (dict_t *dict, uint64_t *sys_hard_limit, - uint64_t *sys_soft_limit) +glusterd_get_rebalance_volfile (glusterd_volinfo_t *volinfo, + char *path, int path_len) { - xlator_t *this = NULL; - - this = THIS; - GF_ASSERT (this); - - GF_ASSERT (dict); + char workdir[PATH_MAX] = {0,}; + glusterd_conf_t *priv = THIS->private; - /* "snap-max-hard-limit" might not be set by user explicitly, - * in that case it's better to consider the default value. - * Hence not erroring out if Key is not found. - */ - if (dict_get_uint64 (dict, GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT, - sys_hard_limit)) { - gf_log (this->name, GF_LOG_DEBUG, "%s is not present in" - "dictionary", - GLUSTERD_STORE_KEY_SNAP_MAX_HARD_LIMIT); - } + GLUSTERD_GET_VOLUME_DIR (workdir, volinfo, priv); - /* "snap-max-soft-limit" might not be set by user explicitly, - * in that case it's better to consider the default value. - * Hence not erroring out if Key is not found. - */ - if (dict_get_uint64 (dict, GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT, - sys_soft_limit)) { - gf_log (this->name, GF_LOG_DEBUG, "%s is not present in" - "dictionary", - GLUSTERD_STORE_KEY_SNAP_MAX_SOFT_LIMIT); - } + snprintf (path, path_len, "%s/%s-rebalance.vol", workdir, + volinfo->volname); } /* This function will update the backend file-system @@ -13699,8 +10058,8 @@ glusterd_update_mntopts (char *brick_path, glusterd_brickinfo_t *brickinfo) { int32_t ret = -1; char *mnt_pt = NULL; - char buff [PATH_MAX] = ""; - char msg [PATH_MAX] = ""; + char buff[PATH_MAX] = ""; + char msg[PATH_MAX] = ""; char *cmd = NULL; struct mntent *entry = NULL; struct mntent save_entry = {0,}; @@ -14081,35 +10440,3 @@ glusterd_op_clear_xaction_peers () } } - -gf_boolean_t -mntopts_exists (const char *str, const char *opts) -{ - char *dup_val = NULL; - char *savetok = NULL; - char *token = NULL; - gf_boolean_t exists = _gf_false; - - GF_ASSERT (opts); - - if (!str || !strlen(str)) - goto out; - - dup_val = gf_strdup (str); - if (!dup_val) - goto out; - - token = strtok_r (dup_val, ",", &savetok); - while (token) { - if (!strcmp (token, opts)) { - exists = _gf_true; - goto out; - } - token = strtok_r (NULL, ",", &savetok); - } - -out: - GF_FREE (dup_val); - return exists; -} - diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index 78a44fda6c7..4062cf1764b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -125,24 +125,12 @@ glusterd_brickinfo_new (glusterd_brickinfo_t **brickinfo); int32_t glusterd_brickinfo_new_from_brick (char *brick, glusterd_brickinfo_t **brickinfo); -int32_t -glusterd_snap_volinfo_find (char *volname, glusterd_snap_t *snap, - glusterd_volinfo_t **volinfo); -int32_t -glusterd_snap_volinfo_find_from_parent_volname (char *origin_volname, - glusterd_snap_t *snap, - glusterd_volinfo_t **volinfo); - int32_t glusterd_volinfo_find (char *volname, glusterd_volinfo_t **volinfo); int glusterd_volinfo_find_by_volume_id (uuid_t volume_id, glusterd_volinfo_t **volinfo); -int -glusterd_snap_volinfo_find_by_volume_id (uuid_t volume_id, - glusterd_volinfo_t **volinfo); - int32_t glusterd_service_stop(const char *service, char *pidfile, int sig, gf_boolean_t force_kill); @@ -426,10 +414,6 @@ glusterd_add_brick_to_dict (glusterd_volinfo_t *volinfo, glusterd_brickinfo_t *brickinfo, dict_t *dict, int32_t count); -int32_t -glusterd_add_snapd_to_dict (glusterd_volinfo_t *volinfo, - dict_t *dict, int32_t count); - int32_t glusterd_get_all_volnames (dict_t *dict); @@ -525,8 +509,6 @@ int glusterd_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict); int glusterd_sys_exec_output_rsp_dict (dict_t *aggr, dict_t *rsp_dict); -int -glusterd_snap_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict); int32_t glusterd_handle_node_rsp (dict_t *req_ctx, void *pending_entry, glusterd_op_t op, dict_t *rsp_dict, dict_t *op_ctx, @@ -686,93 +668,12 @@ glusterd_get_mnt_entry_info (char *mnt_pt, char *buff, int buflen, int glusterd_get_brick_root (char *path, char **mount_point); - -int -glusterd_compare_snap_time(struct list_head *, struct list_head *); - -int -glusterd_compare_snap_vol_time(struct list_head *, struct list_head *); - -int32_t -glusterd_snap_volinfo_restore (dict_t *dict, dict_t *rsp_dict, - glusterd_volinfo_t *new_volinfo, - glusterd_volinfo_t *snap_volinfo, - int32_t volcount); - int32_t glusterd_lvm_snapshot_remove (dict_t *rsp_dict, glusterd_volinfo_t *snap_vol); -int32_t -glusterd_missed_snapinfo_new (glusterd_missed_snap_info **missed_snapinfo); - -int32_t -glusterd_missed_snap_op_new (glusterd_snap_op_t **snap_op); - -int32_t -glusterd_add_missed_snaps_to_dict (dict_t *rsp_dict, - glusterd_volinfo_t *snap_vol, - glusterd_brickinfo_t *brickinfo, - int32_t brick_number, int32_t op); - -int32_t -glusterd_add_missed_snaps_to_export_dict (dict_t *peer_data); - -int32_t -glusterd_import_friend_missed_snap_list (dict_t *peer_data); - -int -gd_restore_snap_volume (dict_t *dict, dict_t *rsp_dict, - glusterd_volinfo_t *orig_vol, - glusterd_volinfo_t *snap_vol, - int32_t volcount); - -int32_t -glusterd_mount_lvm_snapshot (glusterd_brickinfo_t *brickinfo, - char *brick_mount_path); - -int32_t -glusterd_umount (const char *path); - -int32_t -glusterd_add_snapshots_to_export_dict (dict_t *peer_data); - -int32_t -glusterd_compare_friend_snapshots (dict_t *peer_data, - glusterd_peerinfo_t *peerinfo); - -int32_t -glusterd_snapobject_delete (glusterd_snap_t *snap); - -int32_t -glusterd_snap_volume_remove (dict_t *rsp_dict, - glusterd_volinfo_t *snap_vol, - gf_boolean_t remove_lvm, - gf_boolean_t force); - -int32_t -glusterd_store_create_snap_dir (glusterd_snap_t *snap); - -int32_t -glusterd_copy_file (const char *source, const char *destination); - -int32_t -glusterd_copy_folder (const char *source, const char *destination); - -int32_t -glusterd_get_geo_rep_session (char *slave_key, char *origin_volname, - dict_t *gsync_slaves_dict, char *session, - char *slave); - -int32_t -glusterd_restore_geo_rep_files (glusterd_volinfo_t *snap_vol); - gf_boolean_t gd_vol_is_geo_rep_active (glusterd_volinfo_t *volinfo); -int32_t -glusterd_copy_quota_files (glusterd_volinfo_t *src_vol, - glusterd_volinfo_t *dest_vol); - int glusterd_recursive_rmdir (const char *delete_path); @@ -786,107 +687,15 @@ int32_t glusterd_take_lvm_snapshot (glusterd_brickinfo_t *brickinfo, char *origin_brick_path); -int32_t -glusterd_snap_quorum_check (dict_t *dict, gf_boolean_t snap_volume, - char **op_errstr, - struct list_head *peers_list); - -int32_t -glusterd_snap_quorum_check_for_create (dict_t *dict, gf_boolean_t snap_volume, - char **op_errstr, - struct list_head *peers_list); - -int32_t -glusterd_volume_quorum_check (glusterd_volinfo_t *volinfo, int64_t index, - dict_t *dict, char *key_prefix, - int8_t snap_force, int32_t quorum_count, - char *quorum_type, char **op_errstr); - -gf_boolean_t -glusterd_volume_quorum_calculate (glusterd_volinfo_t *volinfo, dict_t *dict, - int down_count, gf_boolean_t first_brick_on, - int8_t snap_force, int32_t quorum_count, - char *quorum_type, char **op_errstr); - -int -glusterd_merge_brick_status (dict_t *dst, dict_t *src); - -int32_t -glusterd_snap_brick_create (glusterd_volinfo_t *snap_volinfo, - glusterd_brickinfo_t *brickinfo, - int32_t brick_count); - void glusterd_launch_synctask (synctask_fn_t fn, void *opaque); int glusterd_enable_default_options (glusterd_volinfo_t *volinfo, char *option); -int -glusterd_snapshot_restore_cleanup (dict_t *rsp_dict, - glusterd_volinfo_t *volinfo, - glusterd_snap_t *snap); - int glusterd_unlink_file (char *sock_file_path); -/* Snapd functions */ -int -glusterd_handle_snapd_option (glusterd_volinfo_t *volinfo); - -int32_t -glusterd_snapd_disconnect (glusterd_volinfo_t *volinfo); - -void -glusterd_get_snapd_dir (glusterd_volinfo_t *volinfo, - char *path, int path_len); - -void -glusterd_get_snapd_rundir (glusterd_volinfo_t *volinfo, - char *path, int path_len); - -void -glusterd_get_snapd_volfile (glusterd_volinfo_t *volinfo, - char *path, int path_len); - -void -glusterd_get_snapd_pidfile (glusterd_volinfo_t *volinfo, - char *path, int path_len); - -void -glusterd_set_snapd_socket_filepath (glusterd_volinfo_t *volinfo, - char *path, int path_len); - -gf_boolean_t -glusterd_is_snapd_running (glusterd_volinfo_t *volinfo); - -int -glusterd_snapd_stop (glusterd_volinfo_t *volinfo); - -int -glusterd_snapd_start (glusterd_volinfo_t *volinfo, gf_boolean_t wait); - -int -glusterd_is_snapd_enabled (glusterd_volinfo_t *volinfo); - -gf_boolean_t -glusterd_is_snapd_online (glusterd_volinfo_t *volinfo); - -void -glusterd_snapd_set_online_status (glusterd_volinfo_t *volinfo, - gf_boolean_t status); - -int -glusterd_restart_snapds (glusterd_conf_t *priv); -/* End snapd functions */ - -int32_t -glusterd_check_and_set_config_limit (glusterd_conf_t *priv); - -int32_t -glusterd_is_snap_soft_limit_reached (glusterd_volinfo_t *volinfo, - dict_t *dict); - int32_t glusterd_find_brick_mount_path (char *brick_path, int32_t brick_count, char **brick_mount_path); @@ -902,17 +711,13 @@ glusterd_update_mntopts (char *brick_path, glusterd_brickinfo_t *brickinfo); int glusterd_update_fs_label (glusterd_brickinfo_t *brickinfo); -void -gd_get_snap_conf_values_if_present (dict_t *opts, uint64_t *sys_hard_limit, - uint64_t *sys_soft_limit); - int glusterd_get_volopt_content (dict_t *dict, gf_boolean_t xml_out); int glusterd_get_default_val_for_volopt (dict_t *dict, gf_boolean_t all_opts, - char *key, char *orig_key, - dict_t *vol_dict, char **err_str); + char *key, char *orig_key, + dict_t *vol_dict, char **err_str); int glusterd_check_client_op_version_support (char *volname, uint32_t op_version, @@ -924,10 +729,25 @@ glusterd_have_peers (); void glusterd_op_clear_xaction_peers (); -gf_boolean_t -mntopts_exists (const char *str, const char *opts); - void glusterd_get_rebalance_volfile (glusterd_volinfo_t *volinfo, char *path, int path_len); + +int32_t +glusterd_brickinfo_dup (glusterd_brickinfo_t *brickinfo, + glusterd_brickinfo_t *dup_brickinfo); + +int +glusterd_vol_add_quota_conf_to_dict (glusterd_volinfo_t *volinfo, dict_t *load, + int vol_idx, char *prefix); + +int32_t +glusterd_import_volinfo (dict_t *peer_data, int count, + glusterd_volinfo_t **volinfo, + char *prefix); + +int +glusterd_import_quota_conf (dict_t *peer_data, int vol_idx, + glusterd_volinfo_t *new_volinfo, + char *prefix); #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.c b/xlators/mgmt/glusterd/src/glusterd-volgen.c index b0c82632c45..37b3677e68b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.c +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.c @@ -34,6 +34,7 @@ #include "glusterd-utils.h" #include "run.h" #include "options.h" +#include "glusterd-snapshot-utils.h" extern struct volopt_map_entry glusterd_volopt_map[]; diff --git a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c index 10a6920ff32..9ac489d5070 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volume-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-volume-ops.c @@ -27,6 +27,7 @@ #include "glusterd-volgen.h" #include "glusterd-messages.h" #include "run.h" +#include "glusterd-snapshot-utils.h" #include #include -- cgit