diff options
author | Jeff Darcy <jdarcy@redhat.com> | 2014-04-28 14:18:50 +0000 |
---|---|---|
committer | Jeff Darcy <jdarcy@redhat.com> | 2014-04-28 14:18:50 +0000 |
commit | e139b4d0ba2286c0d4d44ba81260c2b287016019 (patch) | |
tree | 0a21f0761528e0f79da0a9f67106eb128ace0cf7 /xlators/mgmt/glusterd/src/glusterd-utils.c | |
parent | 73b60c87ca7f62517a8466431f5a8cf167589c8c (diff) | |
parent | f2bac9f9d5b9956969ddd25a54bc636b82f6923e (diff) |
Conflicts:
rpc/xdr/src/glusterfs3-xdr.c
rpc/xdr/src/glusterfs3-xdr.h
xlators/features/changelog/src/Makefile.am
xlators/features/changelog/src/changelog-helpers.h
xlators/features/changelog/src/changelog.c
xlators/mgmt/glusterd/src/glusterd-sm.c
Change-Id: I9972a5e6184503477eb77a8b56c50a4db4eec3e2
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-utils.c')
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-utils.c | 1648 |
1 files changed, 1407 insertions, 241 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index 8e96be91b..7883a98bf 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -13,6 +13,12 @@ #endif #include <inttypes.h> +#if !defined(__NetBSD__) && !defined(GF_DARWIN_HOST_OS) +#include <mntent.h> +#else +#include "mntent_compat.h" +#endif + #include "globals.h" #include "glusterfs.h" #include "compat.h" @@ -44,7 +50,6 @@ #include <inttypes.h> #include <signal.h> #include <sys/types.h> -#include <net/if.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <rpc/pmap_clnt.h> @@ -56,11 +61,6 @@ #include <lvm2app.h> #endif - -#ifdef GF_LINUX_HOST_OS -#include <mntent.h> -#endif - #ifdef GF_SOLARIS_HOST_OS #include <sys/sockio.h> #endif @@ -709,7 +709,7 @@ glusterd_snap_volinfo_restore (dict_t *rsp_dict, /* Adding missed delete to the dict */ ret = glusterd_add_missed_snaps_to_dict (rsp_dict, - snap_volinfo->volname, + snap_volinfo, brickinfo, brick_count + 1, GF_SNAP_OPTION_TYPE_RESTORE); @@ -2241,12 +2241,17 @@ 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 + */ int32_t glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, - dict_t *dict, int32_t count) + dict_t *dict, int32_t count, + char *prefix) { int32_t ret = -1; - char prefix[512] = {0,}; + char pfx[512] = {0,}; char key[512] = {0,}; glusterd_brickinfo_t *brickinfo = NULL; int32_t i = 1; @@ -2263,89 +2268,101 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, GF_ASSERT (this); GF_ASSERT (dict); GF_ASSERT (volinfo); + GF_ASSERT (prefix); - snprintf (key, sizeof (key), "volume%d.name", count); + snprintf (key, sizeof (key), "%s%d.name", prefix, count); ret = dict_set_str (dict, key, volinfo->volname); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.type", count); + snprintf (key, sizeof (key), "%s%d.type", prefix, count); ret = dict_set_int32 (dict, key, volinfo->type); if (ret) goto out; - snprintf (key, sizeof (key), "volume%d.is_volume_restored", count); - ret = dict_set_int32 (dict, key, volinfo->is_volume_restored); - if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Failed to set " - "is_volume_restored option for %s volume", - volinfo->volname); + snprintf (key, sizeof (key), "volume%d.restored_from_snap", count); + ret = dict_set_dynstr_with_alloc + (dict, key, + uuid_utoa (volinfo->restored_from_snap)); + if (ret) goto out; + + if (strlen (volinfo->parent_volname) > 0) { + snprintf (key, sizeof (key), "%s%d.parent_volname", + prefix, count); + ret = dict_set_dynstr_with_alloc (dict, key, + volinfo->parent_volname); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set parent_volname for %s", + volinfo->volname); + goto out; + } } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick_count", count); + snprintf (key, sizeof (key), "%s%d.brick_count", prefix, count); ret = dict_set_int32 (dict, key, volinfo->brick_count); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.version", count); + snprintf (key, sizeof (key), "%s%d.version", prefix, count); ret = dict_set_int32 (dict, key, volinfo->version); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.status", count); + snprintf (key, sizeof (key), "%s%d.status", prefix, count); ret = dict_set_int32 (dict, key, volinfo->status); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.sub_count", count); + snprintf (key, sizeof (key), "%s%d.sub_count", prefix, count); ret = dict_set_int32 (dict, key, volinfo->sub_count); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.stripe_count", count); + snprintf (key, sizeof (key), "%s%d.stripe_count", prefix, count); ret = dict_set_int32 (dict, key, volinfo->stripe_count); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.replica_count", count); + snprintf (key, sizeof (key), "%s%d.replica_count", prefix, count); ret = dict_set_int32 (dict, key, volinfo->replica_count); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.dist_count", count); + snprintf (key, sizeof (key), "%s%d.dist_count", prefix, count); ret = dict_set_int32 (dict, key, volinfo->dist_leaf_count); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.ckusm", count); + snprintf (key, sizeof (key), "%s%d.ckusm", prefix, count); ret = dict_set_int64 (dict, key, volinfo->cksum); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.transport_type", count); + snprintf (key, sizeof (key), "%s%d.transport_type", prefix, count); ret = dict_set_uint32 (dict, key, volinfo->transport_type); if (ret) goto out; - snprintf (key, sizeof (key), "volume%d.is_snap_volume", count); + snprintf (key, sizeof (key), "%s%d.is_snap_volume", prefix, count); ret = dict_set_uint32 (dict, key, volinfo->is_snap_volume); if (ret) { gf_log (THIS->name, GF_LOG_ERROR, "Unable to set %s", key); goto out; } - snprintf (key, sizeof (key), "volume%d.snap-max-hard-limit", count); + snprintf (key, sizeof (key), "%s%d.snap-max-hard-limit", prefix, count); ret = dict_set_uint64 (dict, key, volinfo->snap_max_hard_limit); if (ret) { gf_log (THIS->name, GF_LOG_ERROR, "Unable to set %s", key); @@ -2358,14 +2375,14 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, goto out; } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.volume_id", count); + snprintf (key, sizeof (key), "%s%d.volume_id", prefix, count); ret = dict_set_dynstr (dict, key, volume_id_str); if (ret) goto out; volume_id_str = NULL; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.username", count); + snprintf (key, sizeof (key), "%s%d.username", prefix, count); str = glusterd_auth_get_username (volinfo); if (str) { ret = dict_set_dynstr (dict, key, gf_strdup (str)); @@ -2374,7 +2391,7 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.password", count); + snprintf (key, sizeof (key), "%s%d.password", prefix, count); str = glusterd_auth_get_password (volinfo); if (str) { ret = dict_set_dynstr (dict, key, gf_strdup (str)); @@ -2383,7 +2400,7 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, } memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d.rebalance", count); + snprintf (key, 256, "%s%d.rebalance", prefix, count); ret = dict_set_int32 (dict, key, volinfo->rebal.defrag_cmd); if (ret) goto out; @@ -2395,22 +2412,22 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, goto out; } memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d.rebalance-id", count); + snprintf (key, 256, "%s%d.rebalance-id", prefix, count); ret = dict_set_dynstr (dict, key, rebalance_id_str); if (ret) goto out; rebalance_id_str = NULL; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.rebalance-op", count); + snprintf (key, sizeof (key), "%s%d.rebalance-op", prefix, count); ret = dict_set_uint32 (dict, key, volinfo->rebal.op); if (ret) goto out; if (volinfo->rebal.dict) { - snprintf (prefix, sizeof (prefix), "volume%d", count); + snprintf (pfx, sizeof (pfx), "%s%d", prefix, count); ctx.dict = dict; - ctx.prefix = prefix; + ctx.prefix = pfx; ctx.opt_count = 1; ctx.key_name = "rebal-dict-key"; ctx.val_name = "rebal-dict-value"; @@ -2425,7 +2442,7 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, } memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d."GLUSTERD_STORE_KEY_RB_STATUS, count); + snprintf (key, 256, "%s%d."GLUSTERD_STORE_KEY_RB_STATUS, prefix, count); ret = dict_set_int32 (dict, key, volinfo->rep_brick.rb_status); if (ret) goto out; @@ -2433,8 +2450,8 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, if (volinfo->rep_brick.rb_status > GF_RB_STATUS_NONE) { memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d."GLUSTERD_STORE_KEY_RB_SRC_BRICK, - count); + snprintf (key, 256, "%s%d."GLUSTERD_STORE_KEY_RB_SRC_BRICK, + prefix, count); gf_asprintf (&src_brick, "%s:%s", volinfo->rep_brick.src_brick->hostname, volinfo->rep_brick.src_brick->path); @@ -2443,8 +2460,8 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, goto out; memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d."GLUSTERD_STORE_KEY_RB_DST_BRICK, - count); + snprintf (key, 256, "%s%d."GLUSTERD_STORE_KEY_RB_DST_BRICK, + prefix, count); gf_asprintf (&dst_brick, "%s:%s", volinfo->rep_brick.dst_brick->hostname, volinfo->rep_brick.dst_brick->path); @@ -2459,16 +2476,16 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.rb_id", count); + snprintf (key, sizeof (key), "%s%d.rb_id", prefix, count); ret = dict_set_dynstr (dict, key, rb_id_str); if (ret) goto out; rb_id_str = NULL; } - snprintf (prefix, sizeof (prefix), "volume%d", count); + snprintf (pfx, sizeof (pfx), "%s%d", prefix, count); ctx.dict = dict; - ctx.prefix = prefix; + ctx.prefix = pfx; ctx.opt_count = 1; ctx.key_name = "key"; ctx.val_name = "value"; @@ -2477,13 +2494,13 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, dict_foreach (volinfo->dict, _add_dict_to_prdict, &ctx); ctx.opt_count--; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.opt-count", count); + snprintf (key, sizeof (key), "%s%d.opt-count", prefix, count); ret = dict_set_int32 (dict, key, ctx.opt_count); if (ret) goto out; ctx.dict = dict; - ctx.prefix = prefix; + ctx.prefix = pfx; ctx.opt_count = 1; ctx.key_name = "slave-num"; ctx.val_name = "slave-val"; @@ -2493,42 +2510,42 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, ctx.opt_count--; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.gsync-count", count); + snprintf (key, sizeof (key), "%s%d.gsync-count", prefix, count); ret = dict_set_int32 (dict, key, ctx.opt_count); if (ret) goto out; list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.hostname", - count, i); + snprintf (key, sizeof (key), "%s%d.brick%d.hostname", + prefix, count, i); ret = dict_set_str (dict, key, brickinfo->hostname); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.path", - count, i); + snprintf (key, sizeof (key), "%s%d.brick%d.path", + prefix, count, i); ret = dict_set_str (dict, key, brickinfo->path); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.decommissioned", - count, i); + snprintf (key, sizeof (key), "%s%d.brick%d.decommissioned", + prefix, count, i); ret = dict_set_int32 (dict, key, brickinfo->decommissioned); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.brick_id", - count, i); + snprintf (key, sizeof (key), "%s%d.brick%d.brick_id", + prefix, count, i); ret = dict_set_str (dict, key, brickinfo->brick_id); if (ret) goto out; - snprintf (key, sizeof (key), "volume%d.brick%d.snap_status", - count, i); + snprintf (key, sizeof (key), "%s%d.brick%d.snap_status", + prefix, count, i); ret = dict_set_int32 (dict, key, brickinfo->snap_status); if (ret) { gf_log (this->name, GF_LOG_ERROR, @@ -2538,8 +2555,8 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, goto out; } - snprintf (key, sizeof (key), "volume%d.brick%d.device_path", - count, i); + snprintf (key, sizeof (key), "%s%d.brick%d.device_path", + prefix, count, i); ret = dict_set_str (dict, key, brickinfo->device_path); if (ret) { gf_log (this->name, GF_LOG_ERROR, @@ -2556,19 +2573,19 @@ glusterd_add_volume_to_dict (glusterd_volinfo_t *volinfo, * in the cluster */ memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.op-version", count); + snprintf (key, sizeof (key), "%s%d.op-version", prefix, count); ret = dict_set_int32 (dict, key, volinfo->op_version); if (ret) goto out; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.client-op-version", count); + snprintf (key, sizeof (key), "%s%d.client-op-version", prefix, count); ret = dict_set_int32 (dict, key, volinfo->client_op_version); if (ret) goto out; /*Add volume Capability (BD Xlator) to dict*/ memset (key, 0 ,sizeof (key)); - snprintf (key, sizeof (key), "volume%d.caps", count); + snprintf (key, sizeof (key), "%s%d.caps", prefix, count); ret = dict_set_int32 (dict, key, volinfo->caps); out: @@ -2576,14 +2593,17 @@ out: GF_FREE (rebalance_id_str); GF_FREE (rb_id_str); - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - + gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); 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 + */ int glusterd_vol_add_quota_conf_to_dict (glusterd_volinfo_t *volinfo, dict_t* load, - int vol_idx) + int vol_idx, char *prefix) { int fd = -1; char *gfid_str = NULL; @@ -2595,6 +2615,7 @@ glusterd_vol_add_quota_conf_to_dict (glusterd_volinfo_t *volinfo, dict_t* load, this = THIS; GF_ASSERT (this); + GF_ASSERT (prefix); ret = glusterd_store_create_quota_conf_sh_on_absence (volinfo); if (ret) @@ -2631,8 +2652,8 @@ glusterd_vol_add_quota_conf_to_dict (glusterd_volinfo_t *volinfo, dict_t* load, goto out; } - snprintf (key, sizeof(key)-1, "volume%d.gfid%d", vol_idx, - gfid_idx); + snprintf (key, sizeof(key)-1, "%s%d.gfid%d", prefix, + vol_idx, gfid_idx); key[sizeof(key)-1] = '\0'; ret = dict_set_dynstr (load, key, gfid_str); if (ret) { @@ -2642,19 +2663,19 @@ glusterd_vol_add_quota_conf_to_dict (glusterd_volinfo_t *volinfo, dict_t* load, gfid_str = NULL; } - snprintf (key, sizeof(key)-1, "volume%d.gfid-count", vol_idx); + snprintf (key, sizeof(key)-1, "%s%d.gfid-count", prefix, vol_idx); key[sizeof(key)-1] = '\0'; ret = dict_set_int32 (load, key, gfid_idx); if (ret) goto out; - snprintf (key, sizeof(key)-1, "volume%d.quota-cksum", vol_idx); + snprintf (key, sizeof(key)-1, "%s%d.quota-cksum", prefix, vol_idx); key[sizeof(key)-1] = '\0'; ret = dict_set_uint32 (load, key, volinfo->quota_conf_cksum); if (ret) goto out; - snprintf (key, sizeof(key)-1, "volume%d.quota-version", vol_idx); + snprintf (key, sizeof(key)-1, "%s%d.quota-version", prefix, vol_idx); key[sizeof(key)-1] = '\0'; ret = dict_set_uint32 (load, key, volinfo->quota_conf_version); if (ret) @@ -2669,7 +2690,237 @@ out: } int32_t -glusterd_build_volume_dict (dict_t **vols) +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; + } + + 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; @@ -2677,27 +2928,31 @@ glusterd_build_volume_dict (dict_t **vols) glusterd_volinfo_t *volinfo = NULL; int32_t count = 0; glusterd_dict_ctx_t ctx = {0}; + xlator_t *this = NULL; - priv = THIS->private; + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); dict = dict_new (); - if (!dict) goto out; list_for_each_entry (volinfo, &priv->volumes, vol_list) { count++; - ret = glusterd_add_volume_to_dict (volinfo, dict, count); + ret = glusterd_add_volume_to_dict (volinfo, dict, count, + "volume"); if (ret) goto out; if (!glusterd_is_volume_quota_enabled (volinfo)) continue; - ret = glusterd_vol_add_quota_conf_to_dict (volinfo, dict, count); + ret = glusterd_vol_add_quota_conf_to_dict (volinfo, dict, + count, "volume"); if (ret) goto out; } - ret = dict_set_int32 (dict, "count", count); if (ret) goto out; @@ -2713,18 +2968,18 @@ glusterd_build_volume_dict (dict_t **vols) if (ret) goto out; - *vols = dict; + *peer_data = dict; out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); if (ret) dict_unref (dict); + gf_log (this->name, GF_LOG_TRACE, "Returning %d", ret); return ret; } int32_t -glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, - char *hostname) +glusterd_compare_friend_volume (dict_t *peer_data, int32_t count, + int32_t *status, char *hostname) { int32_t ret = -1; @@ -2737,14 +2992,14 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, int32_t version = 0; xlator_t *this = NULL; - GF_ASSERT (vols); + GF_ASSERT (peer_data); GF_ASSERT (status); this = THIS; GF_ASSERT (this); snprintf (key, sizeof (key), "volume%d.name", count); - ret = dict_get_str (vols, key, &volname); + ret = dict_get_str (peer_data, key, &volname); if (ret) goto out; @@ -2758,7 +3013,7 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "volume%d.version", count); - ret = dict_get_int32 (vols, key, &version); + ret = dict_get_int32 (peer_data, key, &version); if (ret) goto out; @@ -2779,7 +3034,7 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, // memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "volume%d.ckusm", count); - ret = dict_get_uint32 (vols, key, &cksum); + ret = dict_get_uint32 (peer_data, key, &cksum); if (ret) goto out; @@ -2794,7 +3049,7 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "volume%d.quota-version", count); - ret = dict_get_uint32 (vols, key, "a_version); + ret = dict_get_uint32 (peer_data, key, "a_version); if (ret) { gf_log (this->name, GF_LOG_DEBUG, "quota-version key absent for" " volume %s in peer %s's response", volinfo->volname, @@ -2822,7 +3077,7 @@ glusterd_compare_friend_volume (dict_t *vols, int32_t count, int32_t *status, // memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "volume%d.quota-cksum", count); - ret = dict_get_uint32 (vols, key, "a_cksum); + ret = dict_get_uint32 (peer_data, key, "a_cksum); if (ret) { gf_log (this->name, GF_LOG_DEBUG, "quota checksum absent for " "volume %s in peer %s's response", volinfo->volname, @@ -2850,7 +3105,7 @@ out: } static int32_t -import_prdict_dict (dict_t *vols, dict_t *dst_dict, char *key_prefix, +import_prdict_dict (dict_t *peer_data, dict_t *dst_dict, char *key_prefix, char *value_prefix, int opt_count, char *prefix) { char key[512] = {0,}; @@ -2865,7 +3120,7 @@ import_prdict_dict (dict_t *vols, dict_t *dst_dict, char *key_prefix, memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "%s.%s%d", prefix, key_prefix, i); - ret = dict_get_str (vols, key, &opt_key); + ret = dict_get_str (peer_data, key, &opt_key); if (ret) { snprintf (msg, sizeof (msg), "Volume dict key not " "specified"); @@ -2875,7 +3130,7 @@ import_prdict_dict (dict_t *vols, dict_t *dst_dict, char *key_prefix, memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "%s.%s%d", prefix, value_prefix, i); - ret = dict_get_str (vols, key, &opt_val); + ret = dict_get_str (peer_data, key, &opt_val); if (ret) { snprintf (msg, sizeof (msg), "Volume dict value not " "specified"); @@ -3163,7 +3418,7 @@ out: } int32_t -glusterd_import_friend_volume_opts (dict_t *vols, int count, +glusterd_import_friend_volume_opts (dict_t *peer_data, int count, glusterd_volinfo_t *volinfo) { char key[512] = {0,}; @@ -3172,9 +3427,12 @@ glusterd_import_friend_volume_opts (dict_t *vols, int count, char msg[2048] = {0}; char volume_prefix[1024] = {0}; + GF_ASSERT (peer_data); + GF_ASSERT (volinfo); + memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "volume%d.opt-count", count); - ret = dict_get_int32 (vols, key, &opt_count); + ret = dict_get_int32 (peer_data, key, &opt_count); if (ret) { snprintf (msg, sizeof (msg), "Volume option count not " "specified for %s", volinfo->volname); @@ -3182,7 +3440,7 @@ glusterd_import_friend_volume_opts (dict_t *vols, int count, } snprintf (volume_prefix, sizeof (volume_prefix), "volume%d", count); - ret = import_prdict_dict (vols, volinfo->dict, "key", "value", + ret = import_prdict_dict (peer_data, volinfo->dict, "key", "value", opt_count, volume_prefix); if (ret) { snprintf (msg, sizeof (msg), "Unable to import options dict " @@ -3192,14 +3450,14 @@ glusterd_import_friend_volume_opts (dict_t *vols, int count, memset (key, 0, sizeof (key)); snprintf (key, sizeof (key), "volume%d.gsync-count", count); - ret = dict_get_int32 (vols, key, &opt_count); + ret = dict_get_int32 (peer_data, key, &opt_count); if (ret) { snprintf (msg, sizeof (msg), "Gsync count not " "specified for %s", volinfo->volname); goto out; } - ret = import_prdict_dict (vols, volinfo->gsync_slaves, "slave-num", + ret = import_prdict_dict (peer_data, volinfo->gsync_slaves, "slave-num", "slave-val", opt_count, volume_prefix); if (ret) { snprintf (msg, sizeof (msg), "Unable to import gsync sessions " @@ -3214,10 +3472,15 @@ 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 + */ int32_t -glusterd_import_new_brick (dict_t *vols, int32_t vol_count, +glusterd_import_new_brick (dict_t *peer_data, int32_t vol_count, int32_t brick_count, - glusterd_brickinfo_t **brickinfo) + glusterd_brickinfo_t **brickinfo, + char *prefix) { char key[512] = {0,}; int ret = -1; @@ -3230,53 +3493,54 @@ glusterd_import_new_brick (dict_t *vols, int32_t vol_count, glusterd_brickinfo_t *new_brickinfo = NULL; char msg[2048] = {0}; - GF_ASSERT (vols); + GF_ASSERT (peer_data); GF_ASSERT (vol_count >= 0); GF_ASSERT (brickinfo); + GF_ASSERT (prefix); memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.hostname", - vol_count, brick_count); - ret = dict_get_str (vols, key, &hostname); + snprintf (key, sizeof (key), "%s%d.brick%d.hostname", + prefix, vol_count, brick_count); + ret = dict_get_str (peer_data, key, &hostname); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload", key); goto out; } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.path", - vol_count, brick_count); - ret = dict_get_str (vols, key, &path); + snprintf (key, sizeof (key), "%s%d.brick%d.path", + prefix, vol_count, brick_count); + ret = dict_get_str (peer_data, key, &path); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload", key); goto out; } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.brick_id", - vol_count, brick_count); - ret = dict_get_str (vols, key, &brick_id); + snprintf (key, sizeof (key), "%s%d.brick%d.brick_id", + prefix, vol_count, brick_count); + ret = dict_get_str (peer_data, key, &brick_id); memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick%d.decommissioned", - vol_count, brick_count); - ret = dict_get_int32 (vols, key, &decommissioned); + snprintf (key, sizeof (key), "%s%d.brick%d.decommissioned", + prefix, vol_count, brick_count); + ret = dict_get_int32 (peer_data, key, &decommissioned); if (ret) { /* For backward compatibility */ ret = 0; } - snprintf (key, sizeof (key), "volume%d.brick%d.snap_status", - vol_count, brick_count); - ret = dict_get_int32 (vols, key, &snap_status); + snprintf (key, sizeof (key), "%s%d.brick%d.snap_status", + prefix, vol_count, brick_count); + ret = dict_get_int32 (peer_data, key, &snap_status); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload", key); goto out; } - snprintf (key, sizeof (key), "volume%d.brick%d.device_path", - vol_count, brick_count); - ret = dict_get_str (vols, key, &snap_device); + snprintf (key, sizeof (key), "%s%d.brick%d.device_path", + prefix, vol_count, brick_count); + ret = dict_get_str (peer_data, key, &snap_device); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload", key); goto out; @@ -3304,22 +3568,28 @@ 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 + */ int32_t -glusterd_import_bricks (dict_t *vols, int32_t vol_count, - glusterd_volinfo_t *new_volinfo) +glusterd_import_bricks (dict_t *peer_data, int32_t vol_count, + glusterd_volinfo_t *new_volinfo, char *prefix) { int ret = -1; int brick_count = 1; int brickid = 0; glusterd_brickinfo_t *new_brickinfo = NULL; - GF_ASSERT (vols); + GF_ASSERT (peer_data); GF_ASSERT (vol_count >= 0); GF_ASSERT (new_volinfo); + GF_ASSERT (prefix); while (brick_count <= new_volinfo->brick_count) { - ret = glusterd_import_new_brick (vols, vol_count, brick_count, - &new_brickinfo); + ret = glusterd_import_new_brick (peer_data, vol_count, + brick_count, + &new_brickinfo, prefix); if (ret) goto out; if (new_brickinfo->brick_id[0] == '\0') @@ -3337,9 +3607,14 @@ 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 + */ static int -glusterd_import_quota_conf (dict_t *vols, int vol_idx, - glusterd_volinfo_t *new_volinfo) +glusterd_import_quota_conf (dict_t *peer_data, int vol_idx, + glusterd_volinfo_t *new_volinfo, + char *prefix) { int gfid_idx = 0; int gfid_count = 0; @@ -3352,6 +3627,8 @@ glusterd_import_quota_conf (dict_t *vols, int vol_idx, this = THIS; GF_ASSERT (this); + GF_ASSERT (peer_data); + GF_ASSERT (prefix); if (!glusterd_is_volume_quota_enabled (new_volinfo)) { (void) glusterd_clean_up_quota_store (new_volinfo); @@ -3368,22 +3645,23 @@ glusterd_import_quota_conf (dict_t *vols, int vol_idx, goto out; } - snprintf (key, sizeof (key)-1, "volume%d.quota-cksum", vol_idx); + snprintf (key, sizeof (key)-1, "%s%d.quota-cksum", prefix, vol_idx); key[sizeof(key)-1] = '\0'; - ret = dict_get_uint32 (vols, key, &new_volinfo->quota_conf_cksum); + ret = dict_get_uint32 (peer_data, key, &new_volinfo->quota_conf_cksum); if (ret) gf_log (this->name, GF_LOG_DEBUG, "Failed to get quota cksum"); - snprintf (key, sizeof (key)-1, "volume%d.quota-version", vol_idx); + snprintf (key, sizeof (key)-1, "%s%d.quota-version", prefix, vol_idx); key[sizeof(key)-1] = '\0'; - ret = dict_get_uint32 (vols, key, &new_volinfo->quota_conf_version); + ret = dict_get_uint32 (peer_data, key, + &new_volinfo->quota_conf_version); if (ret) gf_log (this->name, GF_LOG_DEBUG, "Failed to get quota " "version"); - snprintf (key, sizeof (key)-1, "volume%d.gfid-count", vol_idx); + snprintf (key, sizeof (key)-1, "%s%d.gfid-count", prefix, vol_idx); key[sizeof(key)-1] = '\0'; - ret = dict_get_int32 (vols, key, &gfid_count); + ret = dict_get_int32 (peer_data, key, &gfid_count); if (ret) goto out; @@ -3397,10 +3675,10 @@ glusterd_import_quota_conf (dict_t *vols, int vol_idx, gfid_idx = 0; for (gfid_idx = 0; gfid_idx < gfid_count; gfid_idx++) { - snprintf (key, sizeof (key)-1, "volume%d.gfid%d", - vol_idx, gfid_idx); + snprintf (key, sizeof (key)-1, "%s%d.gfid%d", + prefix, vol_idx, gfid_idx); key[sizeof(key)-1] = '\0'; - ret = dict_get_str (vols, key, &gfid_str); + ret = dict_get_str (peer_data, key, &gfid_str); if (ret) goto out; @@ -3481,15 +3759,22 @@ 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 + */ int32_t -glusterd_import_volinfo (dict_t *vols, int count, - glusterd_volinfo_t **volinfo) +glusterd_import_volinfo (dict_t *peer_data, int count, + glusterd_volinfo_t **volinfo, + char *prefix) { int ret = -1; char key[256] = {0}; + char *parent_volname = NULL; char *volname = NULL; glusterd_volinfo_t *new_volinfo = NULL; char *volume_id_str = NULL; + char *restored_snap = NULL; char msg[2048] = {0}; char *src_brick = NULL; char *dst_brick = NULL; @@ -3501,50 +3786,49 @@ glusterd_import_volinfo (dict_t *vols, int count, int client_op_version = 0; uint32_t is_snap_volume = 0; - GF_ASSERT (vols); + GF_ASSERT (peer_data); GF_ASSERT (volinfo); + GF_ASSERT (prefix); - snprintf (key, sizeof (key), "volume%d.name", count); - ret = dict_get_str (vols, key, &volname); + snprintf (key, sizeof (key), "%s%d.name", prefix, count); + ret = dict_get_str (peer_data, key, &volname); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload", key); goto out; } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.is_snap_volume", count); - ret = dict_get_uint32 (vols, key, &is_snap_volume); + snprintf (key, sizeof (key), "%s%d.is_snap_volume", prefix, count); + ret = dict_get_uint32 (peer_data, key, &is_snap_volume); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); goto out; } - if (is_snap_volume == _gf_true) { - gf_log (THIS->name, GF_LOG_DEBUG, - "Not syncing snap volume %s", volname); - ret = 0; - goto out; - } - ret = glusterd_volinfo_new (&new_volinfo); if (ret) goto out; strncpy (new_volinfo->volname, volname, sizeof (new_volinfo->volname)); - memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.type", count); - ret = dict_get_int32 (vols, key, &new_volinfo->type); + snprintf (key, sizeof (key), "%s%d.type", prefix, count); + ret = dict_get_int32 (peer_data, key, &new_volinfo->type); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); goto out; } + snprintf (key, sizeof (key), "%s%d.parent_volname", prefix, count); + ret = dict_get_str (peer_data, key, &parent_volname); + if (!ret) + strncpy (new_volinfo->parent_volname, parent_volname, + sizeof(new_volinfo->parent_volname)); + memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.brick_count", count); - ret = dict_get_int32 (vols, key, &new_volinfo->brick_count); + snprintf (key, sizeof (key), "%s%d.brick_count", prefix, count); + ret = dict_get_int32 (peer_data, key, &new_volinfo->brick_count); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3552,8 +3836,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.version", count); - ret = dict_get_int32 (vols, key, &new_volinfo->version); + snprintf (key, sizeof (key), "%s%d.version", prefix, count); + ret = dict_get_int32 (peer_data, key, &new_volinfo->version); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3561,8 +3845,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.status", count); - ret = dict_get_int32 (vols, key, (int32_t *)&new_volinfo->status); + snprintf (key, sizeof (key), "%s%d.status", prefix, count); + ret = dict_get_int32 (peer_data, key, (int32_t *)&new_volinfo->status); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3570,8 +3854,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.sub_count", count); - ret = dict_get_int32 (vols, key, &new_volinfo->sub_count); + snprintf (key, sizeof (key), "%s%d.sub_count", prefix, count); + ret = dict_get_int32 (peer_data, key, &new_volinfo->sub_count); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3581,8 +3865,8 @@ glusterd_import_volinfo (dict_t *vols, int count, /* not having a 'stripe_count' key is not a error (as peer may be of old version) */ memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.stripe_count", count); - ret = dict_get_int32 (vols, key, &new_volinfo->stripe_count); + snprintf (key, sizeof (key), "%s%d.stripe_count", prefix, count); + ret = dict_get_int32 (peer_data, key, &new_volinfo->stripe_count); if (ret) gf_log (THIS->name, GF_LOG_INFO, "peer is possibly old version"); @@ -3590,8 +3874,8 @@ glusterd_import_volinfo (dict_t *vols, int count, /* not having a 'replica_count' key is not a error (as peer may be of old version) */ memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.replica_count", count); - ret = dict_get_int32 (vols, key, &new_volinfo->replica_count); + snprintf (key, sizeof (key), "%s%d.replica_count", prefix, count); + ret = dict_get_int32 (peer_data, key, &new_volinfo->replica_count); if (ret) gf_log (THIS->name, GF_LOG_INFO, "peer is possibly old version"); @@ -3599,16 +3883,16 @@ glusterd_import_volinfo (dict_t *vols, int count, /* not having a 'dist_count' key is not a error (as peer may be of old version) */ memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.dist_count", count); - ret = dict_get_int32 (vols, key, &new_volinfo->dist_leaf_count); + snprintf (key, sizeof (key), "%s%d.dist_count", prefix, count); + ret = dict_get_int32 (peer_data, key, &new_volinfo->dist_leaf_count); if (ret) gf_log (THIS->name, GF_LOG_INFO, "peer is possibly old version"); new_volinfo->subvol_count = new_volinfo->brick_count/ glusterd_get_dist_leaf_count (new_volinfo); memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.ckusm", count); - ret = dict_get_uint32 (vols, key, &new_volinfo->cksum); + snprintf (key, sizeof (key), "%s%d.ckusm", prefix, count); + ret = dict_get_uint32 (peer_data, key, &new_volinfo->cksum); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3616,8 +3900,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.volume_id", count); - ret = dict_get_str (vols, key, &volume_id_str); + snprintf (key, sizeof (key), "%s%d.volume_id", prefix, count); + ret = dict_get_str (peer_data, key, &volume_id_str); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3627,8 +3911,8 @@ glusterd_import_volinfo (dict_t *vols, int count, uuid_parse (volume_id_str, new_volinfo->volume_id); memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.username", count); - ret = dict_get_str (vols, key, &str); + snprintf (key, sizeof (key), "%s%d.username", prefix, count); + ret = dict_get_str (peer_data, key, &str); if (!ret) { ret = glusterd_auth_set_username (new_volinfo, str); if (ret) @@ -3636,8 +3920,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.password", count); - ret = dict_get_str (vols, key, &str); + snprintf (key, sizeof (key), "%s%d.password", prefix, count); + ret = dict_get_str (peer_data, key, &str); if (!ret) { ret = glusterd_auth_set_password (new_volinfo, str); if (ret) @@ -3645,8 +3929,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.transport_type", count); - ret = dict_get_uint32 (vols, key, &new_volinfo->transport_type); + snprintf (key, sizeof (key), "%s%d.transport_type", prefix, count); + ret = dict_get_uint32 (peer_data, key, &new_volinfo->transport_type); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3655,17 +3939,19 @@ glusterd_import_volinfo (dict_t *vols, int count, new_volinfo->is_snap_volume = is_snap_volume; - snprintf (key, sizeof (key), "volume%d.is_volume_restored", count); - ret = dict_get_uint32 (vols, key, &new_volinfo->is_volume_restored); + snprintf (key, sizeof (key), "%s%d.restored_from_snap", prefix, count); + ret = dict_get_str (peer_data, key, &restored_snap); if (ret) { - gf_log (THIS->name, GF_LOG_ERROR, "Failed to get " - "is_volume_restored option for %s", - volname); + snprintf (msg, sizeof (msg), "%s missing in payload for %s", + key, volname); goto out; } - snprintf (key, sizeof (key), "volume%d.snap-max-hard-limit", count); - ret = dict_get_uint64 (vols, key, &new_volinfo->snap_max_hard_limit); + uuid_parse (restored_snap, new_volinfo->restored_from_snap); + + snprintf (key, sizeof (key), "%s%d.snap-max-hard-limit", prefix, count); + ret = dict_get_uint64 (peer_data, key, + &new_volinfo->snap_max_hard_limit); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3673,8 +3959,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.rebalance", count); - ret = dict_get_uint32 (vols, key, &new_volinfo->rebal.defrag_cmd); + snprintf (key, sizeof (key), "%s%d.rebalance", prefix, count); + ret = dict_get_uint32 (peer_data, key, &new_volinfo->rebal.defrag_cmd); if (ret) { snprintf (msg, sizeof (msg), "%s missing in payload for %s", key, volname); @@ -3682,8 +3968,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.rebalance-id", count); - ret = dict_get_str (vols, key, &rebalance_id_str); + snprintf (key, sizeof (key), "%s%d.rebalance-id", prefix, count); + ret = dict_get_str (peer_data, key, &rebalance_id_str); if (ret) { /* This is not present in older glusterfs versions, * so don't error out @@ -3694,15 +3980,17 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.rebalance-op", count); - ret = dict_get_uint32 (vols, key,(uint32_t *) &new_volinfo->rebal.op); + snprintf (key, sizeof (key), "%s%d.rebalance-op", prefix, count); + ret = dict_get_uint32 (peer_data, key, + (uint32_t *) &new_volinfo->rebal.op); if (ret) { /* This is not present in older glusterfs versions, * so don't error out */ ret = 0; } - ret = gd_import_friend_volume_rebal_dict (vols, count, new_volinfo); + ret = gd_import_friend_volume_rebal_dict (peer_data, count, + new_volinfo); if (ret) { snprintf (msg, sizeof (msg), "Failed to import rebalance dict " "for volume."); @@ -3710,8 +3998,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d."GLUSTERD_STORE_KEY_RB_STATUS, count); - ret = dict_get_int32 (vols, key, &rb_status); + snprintf (key, 256, "%s%d."GLUSTERD_STORE_KEY_RB_STATUS, prefix, count); + ret = dict_get_int32 (peer_data, key, &rb_status); if (ret) goto out; new_volinfo->rep_brick.rb_status = rb_status; @@ -3719,9 +4007,9 @@ glusterd_import_volinfo (dict_t *vols, int count, if (new_volinfo->rep_brick.rb_status > GF_RB_STATUS_NONE) { memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d."GLUSTERD_STORE_KEY_RB_SRC_BRICK, - count); - ret = dict_get_str (vols, key, &src_brick); + snprintf (key, 256, "%s%d."GLUSTERD_STORE_KEY_RB_SRC_BRICK, + prefix, count); + ret = dict_get_str (peer_data, key, &src_brick); if (ret) goto out; @@ -3734,9 +4022,9 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, 256, "volume%d."GLUSTERD_STORE_KEY_RB_DST_BRICK, - count); - ret = dict_get_str (vols, key, &dst_brick); + snprintf (key, 256, "%s%d."GLUSTERD_STORE_KEY_RB_DST_BRICK, + prefix, count); + ret = dict_get_str (peer_data, key, &dst_brick); if (ret) goto out; @@ -3749,8 +4037,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.rb_id", count); - ret = dict_get_str (vols, key, &rb_id_str); + snprintf (key, sizeof (key), "%s%d.rb_id", prefix, count); + ret = dict_get_str (peer_data, key, &rb_id_str); if (ret) { /* This is not present in older glusterfs versions, * so don't error out @@ -3762,7 +4050,8 @@ glusterd_import_volinfo (dict_t *vols, int count, } - ret = glusterd_import_friend_volume_opts (vols, count, new_volinfo); + ret = glusterd_import_friend_volume_opts (peer_data, count, + new_volinfo); if (ret) goto out; @@ -3775,13 +4064,13 @@ glusterd_import_volinfo (dict_t *vols, int count, * present. Only one being present is a failure */ memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.op-version", count); - ret = dict_get_int32 (vols, key, &op_version); + snprintf (key, sizeof (key), "%s%d.op-version", prefix, count); + ret = dict_get_int32 (peer_data, key, &op_version); if (ret) ret = 0; memset (key, 0, sizeof (key)); - snprintf (key, sizeof (key), "volume%d.client-op-version", count); - ret = dict_get_int32 (vols, key, &client_op_version); + snprintf (key, sizeof (key), "%s%d.client-op-version", prefix, count); + ret = dict_get_int32 (peer_data, key, &client_op_version); if (ret) ret = 0; @@ -3800,11 +4089,11 @@ glusterd_import_volinfo (dict_t *vols, int count, } memset (key, 0 ,sizeof (key)); - snprintf (key, sizeof (key), "volume%d.caps", count); + snprintf (key, sizeof (key), "%s%d.caps", prefix, count); /*This is not present in older glusterfs versions, so ignore ret value*/ - ret = dict_get_int32 (vols, key, &new_volinfo->caps); + ret = dict_get_int32 (peer_data, key, &new_volinfo->caps); - ret = glusterd_import_bricks (vols, count, new_volinfo); + ret = glusterd_import_bricks (peer_data, count, new_volinfo, prefix); if (ret) goto out; @@ -3881,7 +4170,11 @@ glusterd_volinfo_stop_stale_bricks (glusterd_volinfo_t *new_volinfo, old_brickinfo->hostname, old_brickinfo->path, new_volinfo, &new_brickinfo); - if (ret) { + /* If the brick is stale, i.e it's not a part of the new volume + * or if it's part of the new volume and is pending a snap, + * then stop the brick process + */ + if (ret || (new_brickinfo->snap_status == -1)) { /*TODO: may need to switch to 'atomic' flavour of * brick_stop, once we make peer rpc program also * synctask enabled*/ @@ -3903,9 +4196,34 @@ int32_t glusterd_delete_stale_volume (glusterd_volinfo_t *stale_volinfo, glusterd_volinfo_t *valid_volinfo) { + int32_t ret = -1; + glusterd_volinfo_t *temp_volinfo = NULL; + glusterd_volinfo_t *voliter = NULL; + xlator_t *this = NULL; + GF_ASSERT (stale_volinfo); GF_ASSERT (valid_volinfo); + /* Copy snap_volumes list from stale_volinfo to valid_volinfo */ + valid_volinfo->snap_count = 0; + list_for_each_entry_safe (voliter, temp_volinfo, + &stale_volinfo->snap_volumes, snapvol_list) { + list_add_tail (&voliter->snapvol_list, + &valid_volinfo->snap_volumes); + valid_volinfo->snap_count++; + } + + if ((!uuid_is_null (stale_volinfo->restored_from_snap)) && + (uuid_compare (stale_volinfo->restored_from_snap, + valid_volinfo->restored_from_snap))) { + ret = glusterd_lvm_snapshot_remove (NULL, stale_volinfo); + if (ret) { + gf_log(this->name, GF_LOG_WARNING, + "Failed to remove lvm snapshot for " + "restored volume %s", stale_volinfo->volname); + } + } + /* If stale volume is in started state, copy the port numbers of the * local bricks if they exist in the valid volume information. * stop stale bricks. Stale volume information is going to be deleted. @@ -3992,7 +4310,7 @@ out: } int32_t -glusterd_import_friend_volume (dict_t *vols, size_t count) +glusterd_import_friend_volume (dict_t *peer_data, size_t count) { int32_t ret = -1; @@ -4001,13 +4319,14 @@ glusterd_import_friend_volume (dict_t *vols, size_t count) glusterd_volinfo_t *old_volinfo = NULL; glusterd_volinfo_t *new_volinfo = NULL; - GF_ASSERT (vols); + GF_ASSERT (peer_data); this = THIS; GF_ASSERT (this); priv = this->private; GF_ASSERT (priv); - ret = glusterd_import_volinfo (vols, count, &new_volinfo); + ret = glusterd_import_volinfo (peer_data, count, + &new_volinfo, "volume"); if (ret) goto out; @@ -4033,7 +4352,8 @@ glusterd_import_friend_volume (dict_t *vols, size_t count) if (ret) goto out; - ret = glusterd_import_quota_conf (vols, count, new_volinfo); + ret = glusterd_import_quota_conf (peer_data, count, + new_volinfo, "volume"); if (ret) goto out; @@ -4045,20 +4365,20 @@ out: } int32_t -glusterd_import_friend_volumes (dict_t *vols) +glusterd_import_friend_volumes (dict_t *peer_data) { int32_t ret = -1; int32_t count = 0; int i = 1; - GF_ASSERT (vols); + GF_ASSERT (peer_data); - ret = dict_get_int32 (vols, "count", &count); + ret = dict_get_int32 (peer_data, "count", &count); if (ret) goto out; while (i <= count) { - ret = glusterd_import_friend_volume (vols, i); + ret = glusterd_import_friend_volume (peer_data, i); if (ret) goto out; i++; @@ -4159,25 +4479,840 @@ out: } int32_t -glusterd_compare_friend_data (dict_t *vols, int32_t *status, char *hostname) +glusterd_perform_missed_op (glusterd_snap_t *snap, int32_t op) { - 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; + dict_t *dict = NULL; + int32_t ret = -1; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *snap_volinfo = NULL; + glusterd_volinfo_t *volinfo = 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: + /* TODO : As of now there is only volume in snapshot. + * Change this when multiple volume snapshot is introduced + */ + snap_volinfo = list_entry (snap->volumes.next, + glusterd_volinfo_t, vol_list); + + /* Find the parent volinfo */ + 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; + } + + /* Bump down the original volinfo's version, coz it would have + * incremented already due to volume handshake + */ + volinfo->version--; + uuid_copy (volinfo->restored_from_snap, null_uuid); + + /* Perform the restore */ + ret = gd_restore_snap_volume (dict, volinfo, snap_volinfo); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, "Failed to restore " + "snap for %s", snap->snapname); + volinfo->version++; + 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; + } - GF_ASSERT (vols); + 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 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->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); + + list_for_each_entry (brickinfo, &snap_vol->bricks, brick_list) { + if (uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + if (brickinfo->snap_status == -1) { + gf_log (this->name, GF_LOG_INFO, + "not starting snap brick %s:%s for " + "for the snap %s (volume: %s)", + brickinfo->hostname, brickinfo->path, + peer_snap_name, parent_volinfo->volname); + continue; + } + + ret = glusterd_brick_start (snap_vol, brickinfo, _gf_true); + if (ret) { + gf_log (this->name, GF_LOG_WARNING, "starting the " + "brick %s:%s for the snap %s (volume: %s) " + "failed", brickinfo->hostname, brickinfo->path, + peer_snap_name, parent_volinfo->volname); + goto out; + } + } + + 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; + } + + 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; + } + + 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 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 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; +} + +int32_t +glusterd_compare_friend_data (dict_t *peer_data, int32_t *status, + char *hostname) +{ + 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 = dict_get_int32 (vols, "count", &count); + ret = dict_get_int32 (peer_data, "count", &count); if (ret) goto out; while (i <= count) { - ret = glusterd_compare_friend_volume (vols, i, status, + ret = glusterd_compare_friend_volume (peer_data, i, status, hostname); if (ret) goto out; @@ -4199,10 +5334,10 @@ glusterd_compare_friend_data (dict_t *vols, int32_t *status, char *hostname) stale_shd = _gf_true; if (glusterd_is_nodesvc_running ("quotad")) stale_qd = _gf_true; - ret = glusterd_import_global_opts (vols); + ret = glusterd_import_global_opts (peer_data); if (ret) goto out; - ret = glusterd_import_friend_volumes (vols); + ret = glusterd_import_friend_volumes (peer_data); if (ret) goto out; if (_gf_false == glusterd_are_all_volumes_stopped ()) { @@ -4218,9 +5353,8 @@ glusterd_compare_friend_data (dict_t *vols, int32_t *status, char *hostname) } out: - gf_log ("", GF_LOG_DEBUG, "Returning with ret: %d, status: %d", - ret, *status); - + gf_log (this->name, GF_LOG_DEBUG, + "Returning with ret: %d, status: %d", ret, *status); return ret; } @@ -4522,14 +5656,16 @@ glusterd_nodesvc_start (char *server, gf_boolean_t wait) "--trace-children=yes", "--track-origins=yes", NULL); runner_argprintf (&runner, "--log-file=%s", valgrind_logfile); - } + } runner_add_args (&runner, SBIN_DIR"/glusterfs", "-s", "localhost", "--volfile-id", volfileid, "-p", pidfile, "-l", logfile, - "-S", sockfpath, NULL); + "-S", sockfpath, + "-L", "DEBUG", + NULL); if (!strcmp (server, "glustershd")) { snprintf (glusterd_uuid_option, sizeof (glusterd_uuid_option), @@ -5456,7 +6592,6 @@ out: return -1; } -#ifdef GF_LINUX_HOST_OS int glusterd_get_brick_root (char *path, char **mount_point) { @@ -5752,7 +6887,6 @@ out: return device; } -#endif int glusterd_add_brick_detail_to_dict (glusterd_volinfo_t *volinfo, @@ -5826,13 +6960,12 @@ glusterd_add_brick_detail_to_dict (glusterd_volinfo_t *volinfo, if (ret) goto out; } -#ifdef GF_LINUX_HOST_OS + ret = glusterd_add_brick_mount_details (brickinfo, dict, count); if (ret) goto out; ret = glusterd_add_inode_size_to_dict (dict, count); -#endif out: if (ret) gf_log (this->name, GF_LOG_DEBUG, "Error adding brick" @@ -8830,7 +9963,7 @@ glusterd_snap_config_use_rsp_dict (dict_t *dst, dict_t *src) } for (i = 0; i < voldisplaycount; i++) { - snprintf (buf, sizeof(buf), "volume%ld-volname", i); + snprintf (buf, sizeof(buf), "volume%"PRIu64"-volname", i); ret = dict_get_str (src, buf, &volname); if (ret) { gf_log ("", GF_LOG_ERROR, @@ -8845,7 +9978,7 @@ glusterd_snap_config_use_rsp_dict (dict_t *dst, dict_t *src) } snprintf (buf, sizeof(buf), - "volume%ld-snap-max-hard-limit", i); + "volume%"PRIu64"-snap-max-hard-limit", i); ret = dict_get_uint64 (src, buf, &value); if (ret) { gf_log ("", GF_LOG_ERROR, @@ -8860,7 +9993,7 @@ glusterd_snap_config_use_rsp_dict (dict_t *dst, dict_t *src) } snprintf (buf, sizeof(buf), - "volume%ld-active-hard-limit", i); + "volume%"PRIu64"-active-hard-limit", i); ret = dict_get_uint64 (src, buf, &value); if (ret) { gf_log ("", GF_LOG_ERROR, @@ -8875,7 +10008,7 @@ glusterd_snap_config_use_rsp_dict (dict_t *dst, dict_t *src) } snprintf (buf, sizeof(buf), - "volume%ld-snap-max-soft-limit", i); + "volume%"PRIu64"-snap-max-soft-limit", i); ret = dict_get_uint64 (src, buf, &value); if (ret) { gf_log ("", GF_LOG_ERROR, @@ -9993,7 +11126,6 @@ glusterd_missed_snapinfo_new (glusterd_missed_snap_info **missed_snapinfo) if (!new_missed_snapinfo) goto out; - new_missed_snapinfo->node_snap_info = NULL; INIT_LIST_HEAD (&new_missed_snapinfo->missed_snaps); INIT_LIST_HEAD (&new_missed_snapinfo->snap_ops); @@ -10023,7 +11155,6 @@ glusterd_missed_snap_op_new (glusterd_snap_op_t **snap_op) if (!new_snap_op) goto out; - new_snap_op->brick_path = NULL; new_snap_op->brick_num = -1; new_snap_op->op = -1; new_snap_op->status = -1; @@ -10376,3 +11507,38 @@ glusterd_compare_volume_name(struct list_head *list1, struct list_head *list2) volinfo2 = list_entry(list2, glusterd_volinfo_t, vol_list); return strcmp(volinfo1->volname, volinfo2->volname); } + +int32_t +glusterd_mount_lvm_snapshot (char *device_path, char *brick_mount_path) +{ + char msg[NAME_MAX] = ""; + int32_t ret = -1; + runner_t runner = {0, }; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + GF_ASSERT (brick_mount_path); + GF_ASSERT (device_path); + + + runinit (&runner); + snprintf (msg, sizeof (msg), "mount -o nouuid %s %s", + device_path, brick_mount_path); + runner_add_args (&runner, "mount", "-o", "nouuid", 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)", device_path, + strerror (errno)); + goto out; + } else + gf_log (this->name, GF_LOG_DEBUG, "mounting the snapshot " + "logical device %s successful", device_path); + +out: + gf_log (this->name, GF_LOG_TRACE, "Returning with %d", ret); + return ret; +} |