summaryrefslogtreecommitdiff
path: root/0510-glusterd-brick_mux-Optimize-friend-handshake-code-to.patch
diff options
context:
space:
mode:
Diffstat (limited to '0510-glusterd-brick_mux-Optimize-friend-handshake-code-to.patch')
-rw-r--r--0510-glusterd-brick_mux-Optimize-friend-handshake-code-to.patch784
1 files changed, 784 insertions, 0 deletions
diff --git a/0510-glusterd-brick_mux-Optimize-friend-handshake-code-to.patch b/0510-glusterd-brick_mux-Optimize-friend-handshake-code-to.patch
new file mode 100644
index 0000000..e8a4906
--- /dev/null
+++ b/0510-glusterd-brick_mux-Optimize-friend-handshake-code-to.patch
@@ -0,0 +1,784 @@
+From 5294c82e0528059b10cbaab7805b20e76ffdd66b Mon Sep 17 00:00:00 2001
+From: mohit84 <moagrawa@redhat.com>
+Date: Mon, 30 Nov 2020 17:39:53 +0530
+Subject: [PATCH 510/511] glusterd[brick_mux]: Optimize friend handshake code
+ to avoid call_bail (#1614)
+
+During glusterd handshake glusterd received a volume dictionary
+from peer end to compare the own volume dictionary data.If the options
+are differ it sets the key to recognize volume options are changed
+and call import syntask to delete/start the volume.In brick_mux
+environment while number of volumes are high(5k) the dict api in function
+glusterd_compare_friend_volume takes time because the function
+glusterd_handle_friend_req saves all peer volume data in a single dictionary.
+Due to time taken by the function glusterd_handle_friend RPC requests receives
+a call_bail from a peer end gluster(CLI) won't be able to show volume status.
+
+Solution: To optimize the code done below changes
+1) Populate a new specific dictionary to save the peer end version specific
+ data so that function won't take much time to take the decision about the
+ peer end has some volume updates.
+2) In case of volume has differ version set the key in status_arr instead
+ of saving in a dictionary to make the operation is faster.
+
+Note: To validate the changes followed below procedure
+1) Setup 5100 distributed volumes 3x1
+2) Enable brick_mux
+3) Start all the volumes
+4) Kill all gluster processes on 3rd node
+5) Run a loop to update volume option on a 1st node
+ for i in {1..5100}; do gluster v set vol$i performance.open-behind off; done
+6) Start the glusterd process on the 3rd node
+7) Wait to finish handshake and check there should not be any call_bail message
+ in the logs
+
+> Change-Id: Ibad7c23988539cc369ecc39dea2ea6985470bee1
+> Fixes: #1613
+> Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
+> (Cherry pick from commit 12545d91eed27ff9abb0505a12c7d4e75b45a53e)
+> (Reviewed on upstream link https://github.com/gluster/glusterfs/issues/1613)
+
+Change-Id: Ibad7c23988539cc369ecc39dea2ea6985470bee1
+BUG: 1898784
+Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
+Reviewed-on: https://code.engineering.redhat.com/gerrit/221193
+Tested-by: RHGS Build Bot <nigelb@redhat.com>
+Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
+---
+ libglusterfs/src/ctx.c | 4 +
+ libglusterfs/src/dict.c | 166 ++++++++++++++++++++++++++-
+ libglusterfs/src/globals.c | 2 -
+ libglusterfs/src/glusterfs/dict.h | 5 +
+ libglusterfs/src/glusterfs/globals.h | 2 +
+ libglusterfs/src/libglusterfs.sym | 1 +
+ xlators/mgmt/glusterd/src/glusterd-handler.c | 39 ++++---
+ xlators/mgmt/glusterd/src/glusterd-sm.c | 6 +-
+ xlators/mgmt/glusterd/src/glusterd-sm.h | 1 +
+ xlators/mgmt/glusterd/src/glusterd-utils.c | 148 ++++++++++++++----------
+ xlators/mgmt/glusterd/src/glusterd-utils.h | 2 +-
+ xlators/mgmt/glusterd/src/glusterd.h | 8 +-
+ 12 files changed, 301 insertions(+), 83 deletions(-)
+
+diff --git a/libglusterfs/src/ctx.c b/libglusterfs/src/ctx.c
+index 4a001c2..ae1a77a 100644
+--- a/libglusterfs/src/ctx.c
++++ b/libglusterfs/src/ctx.c
+@@ -14,6 +14,7 @@
+ #include "glusterfs/glusterfs.h"
+ #include "timer-wheel.h"
+
++glusterfs_ctx_t *global_ctx = NULL;
+ glusterfs_ctx_t *
+ glusterfs_ctx_new()
+ {
+@@ -51,6 +52,9 @@ glusterfs_ctx_new()
+ GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, 0);
+ GF_ATOMIC_INIT(ctx->stats.total_pairs_used, 0);
+ GF_ATOMIC_INIT(ctx->stats.total_dicts_used, 0);
++
++ if (!global_ctx)
++ global_ctx = ctx;
+ out:
+ return ctx;
+ }
+diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c
+index d8cdda4..e5f619c 100644
+--- a/libglusterfs/src/dict.c
++++ b/libglusterfs/src/dict.c
+@@ -56,7 +56,13 @@ struct dict_cmp {
+ static data_t *
+ get_new_data()
+ {
+- data_t *data = mem_get(THIS->ctx->dict_data_pool);
++ data_t *data = NULL;
++
++ if (global_ctx) {
++ data = mem_get(global_ctx->dict_data_pool);
++ } else {
++ data = mem_get(THIS->ctx->dict_data_pool);
++ }
+
+ if (!data)
+ return NULL;
+@@ -3503,3 +3509,161 @@ unlock:
+ UNLOCK(&dict->lock);
+ return 0;
+ }
++
++/* Popluate specific dictionary on the basis of passed key array at the
++ time of unserialize buffer
++*/
++int32_t
++dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,
++ char **suffix_key_arr, dict_t **specific_dict,
++ int totkeycount)
++{
++ char *buf = orig_buf;
++ int ret = -1;
++ int32_t count = 0;
++ int i = 0;
++ int j = 0;
++
++ data_t *value = NULL;
++ char *key = NULL;
++ int32_t keylen = 0;
++ int32_t vallen = 0;
++ int32_t hostord = 0;
++ xlator_t *this = NULL;
++ int32_t keylenarr[totkeycount];
++
++ this = THIS;
++ GF_ASSERT(this);
++
++ if (!buf) {
++ gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
++ "buf is null!");
++ goto out;
++ }
++
++ if (size == 0) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
++ "size is 0!");
++ goto out;
++ }
++
++ if (!fill) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
++ "fill is null!");
++ goto out;
++ }
++
++ if (!*fill) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
++ "*fill is null!");
++ goto out;
++ }
++
++ if ((buf + DICT_HDR_LEN) > (orig_buf + size)) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
++ "undersized buffer "
++ "passed. available (%lu) < required (%lu)",
++ (long)(orig_buf + size), (long)(buf + DICT_HDR_LEN));
++ goto out;
++ }
++
++ memcpy(&hostord, buf, sizeof(hostord));
++ count = ntoh32(hostord);
++ buf += DICT_HDR_LEN;
++
++ if (count < 0) {
++ gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_COUNT_LESS_THAN_ZERO,
++ "count=%d", count, NULL);
++ goto out;
++ }
++
++ /* Compute specific key length and save in array */
++ for (i = 0; i < totkeycount; i++) {
++ keylenarr[i] = strlen(suffix_key_arr[i]);
++ }
++
++ for (i = 0; i < count; i++) {
++ if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
++ "undersized "
++ "buffer passed. available (%lu) < "
++ "required (%lu)",
++ (long)(orig_buf + size),
++ (long)(buf + DICT_DATA_HDR_KEY_LEN));
++ goto out;
++ }
++ memcpy(&hostord, buf, sizeof(hostord));
++ keylen = ntoh32(hostord);
++ buf += DICT_DATA_HDR_KEY_LEN;
++
++ if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
++ "undersized "
++ "buffer passed. available (%lu) < "
++ "required (%lu)",
++ (long)(orig_buf + size),
++ (long)(buf + DICT_DATA_HDR_VAL_LEN));
++ goto out;
++ }
++ memcpy(&hostord, buf, sizeof(hostord));
++ vallen = ntoh32(hostord);
++ buf += DICT_DATA_HDR_VAL_LEN;
++
++ if ((keylen < 0) || (vallen < 0)) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
++ "undersized length passed "
++ "key:%d val:%d",
++ keylen, vallen);
++ goto out;
++ }
++ if ((buf + keylen) > (orig_buf + size)) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
++ "undersized buffer passed. "
++ "available (%lu) < required (%lu)",
++ (long)(orig_buf + size), (long)(buf + keylen));
++ goto out;
++ }
++ key = buf;
++ buf += keylen + 1; /* for '\0' */
++
++ if ((buf + vallen) > (orig_buf + size)) {
++ gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
++ "undersized buffer passed. "
++ "available (%lu) < required (%lu)",
++ (long)(orig_buf + size), (long)(buf + vallen));
++ goto out;
++ }
++ value = get_new_data();
++
++ if (!value) {
++ ret = -1;
++ goto out;
++ }
++ value->len = vallen;
++ value->data = gf_memdup(buf, vallen);
++ value->data_type = GF_DATA_TYPE_STR_OLD;
++ value->is_static = _gf_false;
++ buf += vallen;
++
++ ret = dict_addn(*fill, key, keylen, value);
++ if (ret < 0) {
++ data_destroy(value);
++ goto out;
++ }
++ for (j = 0; j < totkeycount; j++) {
++ if (keylen > keylenarr[j]) {
++ if (!strcmp(key + keylen - keylenarr[j], suffix_key_arr[j])) {
++ ret = dict_addn(*specific_dict, key, keylen, value);
++ break;
++ }
++ }
++ }
++
++ if (ret < 0)
++ goto out;
++ }
++
++ ret = 0;
++out:
++ return ret;
++}
+diff --git a/libglusterfs/src/globals.c b/libglusterfs/src/globals.c
+index e433ee8..30c15b6 100644
+--- a/libglusterfs/src/globals.c
++++ b/libglusterfs/src/globals.c
+@@ -96,7 +96,6 @@ const char *gf_upcall_list[GF_UPCALL_FLAGS_MAXVALUE] = {
+ /* This global ctx is a bad hack to prevent some of the libgfapi crashes.
+ * This should be removed once the patch on resource pool is accepted
+ */
+-glusterfs_ctx_t *global_ctx = NULL;
+ pthread_mutex_t global_ctx_mutex = PTHREAD_MUTEX_INITIALIZER;
+ xlator_t global_xlator;
+ static int gf_global_mem_acct_enable = 1;
+@@ -236,7 +235,6 @@ __glusterfs_this_location()
+ if (*this_location == NULL) {
+ thread_xlator = &global_xlator;
+ }
+-
+ return this_location;
+ }
+
+diff --git a/libglusterfs/src/glusterfs/dict.h b/libglusterfs/src/glusterfs/dict.h
+index 8239c7a..6e469c7 100644
+--- a/libglusterfs/src/glusterfs/dict.h
++++ b/libglusterfs/src/glusterfs/dict.h
+@@ -423,4 +423,9 @@ dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result);
+
+ int
+ dict_serialized_length_lk(dict_t *this);
++
++int32_t
++dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,
++ char **specific_key_arr, dict_t **specific_dict,
++ int totkeycount);
+ #endif
+diff --git a/libglusterfs/src/glusterfs/globals.h b/libglusterfs/src/glusterfs/globals.h
+index cc145cd..33fb023 100644
+--- a/libglusterfs/src/glusterfs/globals.h
++++ b/libglusterfs/src/glusterfs/globals.h
+@@ -199,4 +199,6 @@ int
+ gf_global_mem_acct_enable_get(void);
+ int
+ gf_global_mem_acct_enable_set(int val);
++
++extern glusterfs_ctx_t *global_ctx;
+ #endif /* !_GLOBALS_H */
+diff --git a/libglusterfs/src/libglusterfs.sym b/libglusterfs/src/libglusterfs.sym
+index d060292..bc770e2 100644
+--- a/libglusterfs/src/libglusterfs.sym
++++ b/libglusterfs/src/libglusterfs.sym
+@@ -436,6 +436,7 @@ dict_clear_flag
+ dict_check_flag
+ dict_unref
+ dict_unserialize
++dict_unserialize_specific_keys
+ drop_token
+ eh_destroy
+ eh_dump
+diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c
+index b8799ab..908361c 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-handler.c
++++ b/xlators/mgmt/glusterd/src/glusterd-handler.c
+@@ -86,6 +86,9 @@ glusterd_big_locked_handler(rpcsvc_request_t *req, rpcsvc_actor actor_fn)
+ return ret;
+ }
+
++static char *specific_key_suffix[] = {".quota-cksum", ".ckusm", ".version",
++ ".quota-version", ".name"};
++
+ static int
+ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
+ int port, gd1_mgmt_friend_req *friend_req)
+@@ -97,6 +100,8 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
+ char rhost[UNIX_PATH_MAX + 1] = {0};
+ uuid_t friend_uuid = {0};
+ dict_t *dict = NULL;
++ dict_t *peer_ver = NULL;
++ int totcount = sizeof(specific_key_suffix) / sizeof(specific_key_suffix[0]);
+
+ gf_uuid_parse(uuid_utoa(uuid), friend_uuid);
+ if (!port)
+@@ -104,8 +109,19 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
+
+ ret = glusterd_remote_hostname_get(req, rhost, sizeof(rhost));
+
++ ctx = GF_CALLOC(1, sizeof(*ctx), gf_gld_mt_friend_req_ctx_t);
++ dict = dict_new();
++ peer_ver = dict_new();
++
+ RCU_READ_LOCK;
+
++ if (!ctx || !dict || !peer_ver) {
++ gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
++ "Unable to allocate memory");
++ ret = -1;
++ goto out;
++ }
++
+ peerinfo = glusterd_peerinfo_find(uuid, rhost);
+
+ if (peerinfo == NULL) {
+@@ -130,28 +146,14 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
+ event->peername = gf_strdup(peerinfo->hostname);
+ gf_uuid_copy(event->peerid, peerinfo->uuid);
+
+- ctx = GF_CALLOC(1, sizeof(*ctx), gf_gld_mt_friend_req_ctx_t);
+-
+- if (!ctx) {
+- gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
+- "Unable to allocate memory");
+- ret = -1;
+- goto out;
+- }
+-
+ gf_uuid_copy(ctx->uuid, uuid);
+ if (hostname)
+ ctx->hostname = gf_strdup(hostname);
+ ctx->req = req;
+
+- dict = dict_new();
+- if (!dict) {
+- ret = -1;
+- goto out;
+- }
+-
+- ret = dict_unserialize(friend_req->vols.vols_val, friend_req->vols.vols_len,
+- &dict);
++ ret = dict_unserialize_specific_keys(
++ friend_req->vols.vols_val, friend_req->vols.vols_len, &dict,
++ specific_key_suffix, &peer_ver, totcount);
+
+ if (ret)
+ goto out;
+@@ -159,6 +161,7 @@ glusterd_handle_friend_req(rpcsvc_request_t *req, uuid_t uuid, char *hostname,
+ dict->extra_stdfree = friend_req->vols.vols_val;
+
+ ctx->vols = dict;
++ ctx->peer_ver = peer_ver;
+ event->ctx = ctx;
+
+ ret = glusterd_friend_sm_inject_event(event);
+@@ -188,6 +191,8 @@ out:
+ } else {
+ free(friend_req->vols.vols_val);
+ }
++ if (peer_ver)
++ dict_unref(peer_ver);
+ if (event)
+ GF_FREE(event->peername);
+ GF_FREE(event);
+diff --git a/xlators/mgmt/glusterd/src/glusterd-sm.c b/xlators/mgmt/glusterd/src/glusterd-sm.c
+index 044da3d..d10a792 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-sm.c
++++ b/xlators/mgmt/glusterd/src/glusterd-sm.c
+@@ -106,6 +106,8 @@ glusterd_destroy_friend_req_ctx(glusterd_friend_req_ctx_t *ctx)
+
+ if (ctx->vols)
+ dict_unref(ctx->vols);
++ if (ctx->peer_ver)
++ dict_unref(ctx->peer_ver);
+ GF_FREE(ctx->hostname);
+ GF_FREE(ctx);
+ }
+@@ -936,8 +938,8 @@ glusterd_ac_handle_friend_add_req(glusterd_friend_sm_event_t *event, void *ctx)
+ // Build comparison logic here.
+ pthread_mutex_lock(&conf->import_volumes);
+ {
+- ret = glusterd_compare_friend_data(ev_ctx->vols, &status,
+- event->peername);
++ ret = glusterd_compare_friend_data(ev_ctx->vols, ev_ctx->peer_ver,
++ &status, event->peername);
+ if (ret) {
+ pthread_mutex_unlock(&conf->import_volumes);
+ goto out;
+diff --git a/xlators/mgmt/glusterd/src/glusterd-sm.h b/xlators/mgmt/glusterd/src/glusterd-sm.h
+index ce008ac..efdf68e 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-sm.h
++++ b/xlators/mgmt/glusterd/src/glusterd-sm.h
+@@ -174,6 +174,7 @@ typedef struct glusterd_friend_req_ctx_ {
+ rpcsvc_request_t *req;
+ int port;
+ dict_t *vols;
++ dict_t *peer_ver; // Dictionary to save peer ver data
+ } glusterd_friend_req_ctx_t;
+
+ typedef struct glusterd_friend_update_ctx_ {
+diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
+index f7030fb..cf32bd9 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
++++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
+@@ -3709,12 +3709,14 @@ out:
+ return ret;
+ }
+
+-int32_t
+-glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
+- int32_t *status, char *hostname)
++static int32_t
++glusterd_compare_friend_volume(dict_t *peer_data,
++ glusterd_friend_synctask_args_t *arg,
++ int32_t count, int32_t *status, char *hostname)
+ {
+ int32_t ret = -1;
+ char key[64] = "";
++ char key_prefix[32];
+ int keylen;
+ glusterd_volinfo_t *volinfo = NULL;
+ char *volname = NULL;
+@@ -3726,15 +3728,20 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
+ xlator_t *this = NULL;
+
+ GF_ASSERT(peer_data);
++ GF_ASSERT(arg);
+ GF_ASSERT(status);
+
+ this = THIS;
+ GF_ASSERT(this);
+
+- keylen = snprintf(key, sizeof(key), "volume%d.name", count);
+- ret = dict_get_strn(peer_data, key, keylen, &volname);
+- if (ret)
++ snprintf(key_prefix, sizeof(key_prefix), "volume%d", count);
++ keylen = snprintf(key, sizeof(key), "%s.name", key_prefix);
++ ret = dict_get_strn(arg->peer_ver_data, key, keylen, &volname);
++ if (ret) {
++ gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
++ "Key=%s is NULL in peer_ver_data", key, NULL);
+ goto out;
++ }
+
+ ret = glusterd_volinfo_find(volname, &volinfo);
+ if (ret) {
+@@ -3750,10 +3757,13 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
+ goto out;
+ }
+
+- keylen = snprintf(key, sizeof(key), "volume%d.version", count);
+- ret = dict_get_int32n(peer_data, key, keylen, &version);
+- if (ret)
++ keylen = snprintf(key, sizeof(key), "%s.version", key_prefix);
++ ret = dict_get_int32n(arg->peer_ver_data, key, keylen, &version);
++ if (ret) {
++ gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
++ "Key=%s is NULL in peer_ver_data", key, NULL);
+ goto out;
++ }
+
+ if (version > volinfo->version) {
+ // Mismatch detected
+@@ -3772,10 +3782,13 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
+
+ // Now, versions are same, compare cksums.
+ //
+- snprintf(key, sizeof(key), "volume%d.ckusm", count);
+- ret = dict_get_uint32(peer_data, key, &cksum);
+- if (ret)
++ snprintf(key, sizeof(key), "%s.ckusm", key_prefix);
++ ret = dict_get_uint32(arg->peer_ver_data, key, &cksum);
++ if (ret) {
++ gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
++ "Key=%s is NULL in peer_ver_data", key, NULL);
+ goto out;
++ }
+
+ if (cksum != volinfo->cksum) {
+ ret = 0;
+@@ -3790,8 +3803,8 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
+ if (!dict_get_sizen(volinfo->dict, VKEY_FEATURES_QUOTA))
+ goto skip_quota;
+
+- snprintf(key, sizeof(key), "volume%d.quota-version", count);
+- ret = dict_get_uint32(peer_data, key, &quota_version);
++ snprintf(key, sizeof(key), "%s.quota-version", key_prefix);
++ ret = dict_get_uint32(arg->peer_ver_data, key, &quota_version);
+ if (ret) {
+ gf_msg_debug(this->name, 0,
+ "quota-version key absent for"
+@@ -3809,6 +3822,7 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
+ "%d on peer %s",
+ volinfo->volname, volinfo->quota_conf_version, quota_version,
+ hostname);
++ GF_ATOMIC_INIT(volinfo->volpeerupdate, 1);
+ *status = GLUSTERD_VOL_COMP_UPDATE_REQ;
+ goto out;
+ } else if (quota_version < volinfo->quota_conf_version) {
+@@ -3819,8 +3833,8 @@ glusterd_compare_friend_volume(dict_t *peer_data, int32_t count,
+
+ // Now, versions are same, compare cksums.
+ //
+- snprintf(key, sizeof(key), "volume%d.quota-cksum", count);
+- ret = dict_get_uint32(peer_data, key, &quota_cksum);
++ snprintf(key, sizeof(key), "%s.quota-cksum", key_prefix);
++ ret = dict_get_uint32(arg->peer_ver_data, key, &quota_cksum);
+ if (ret) {
+ gf_msg_debug(this->name, 0,
+ "quota checksum absent for "
+@@ -3846,13 +3860,12 @@ skip_quota:
+ *status = GLUSTERD_VOL_COMP_SCS;
+
+ out:
+- keylen = snprintf(key, sizeof(key), "volume%d.update", count);
+-
+ if (*status == GLUSTERD_VOL_COMP_UPDATE_REQ) {
+- ret = dict_set_int32n(peer_data, key, keylen, 1);
+- } else {
+- ret = dict_set_int32n(peer_data, key, keylen, 0);
++ /*Set the status to ensure volume is updated on the peer
++ */
++ arg->status_arr[(count / 64)] ^= 1UL << (count % 64);
+ }
++
+ if (*status == GLUSTERD_VOL_COMP_RJT) {
+ gf_event(EVENT_COMPARE_FRIEND_VOLUME_FAILED, "volume=%s",
+ volinfo->volname);
+@@ -4935,8 +4948,9 @@ out:
+ return ret;
+ }
+
+-int32_t
+-glusterd_import_friend_volume(dict_t *peer_data, int count)
++static int32_t
++glusterd_import_friend_volume(dict_t *peer_data, int count,
++ glusterd_friend_synctask_args_t *arg)
+ {
+ int32_t ret = -1;
+ glusterd_conf_t *priv = NULL;
+@@ -4954,10 +4968,27 @@ glusterd_import_friend_volume(dict_t *peer_data, int count)
+ priv = this->private;
+ GF_ASSERT(priv);
+
+- ret = snprintf(key, sizeof(key), "volume%d.update", count);
+- ret = dict_get_int32n(peer_data, key, ret, &update);
+- if (ret || !update) {
++ if (arg) {
++ /*Check if the volume options are updated on the other peers
++ */
++ update = (1UL & (arg->status_arr[(count / 64)] >> (count % 64)));
++ } else {
++ ret = snprintf(key, sizeof(key), "volume%d.update", count);
++ ret = dict_get_int32n(peer_data, key, ret, &update);
++ if (ret) {
++ gf_smsg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
++ "Key=%s", key, NULL);
++ goto out;
++ }
++ }
++
++ if (!update) {
+ /* if update is 0 that means the volume is not imported */
++ gf_log(this->name, GF_LOG_DEBUG,
++ "The volume%d does"
++ " not have any peer change",
++ count);
++ ret = 0;
+ goto out;
+ }
+
+@@ -5045,6 +5076,8 @@ glusterd_import_friend_volumes_synctask(void *opaque)
+ glusterd_conf_t *conf = NULL;
+ dict_t *peer_data = NULL;
+ glusterd_friend_synctask_args_t *arg = NULL;
++ uint64_t bm = 0;
++ uint64_t mask = 0;
+
+ this = THIS;
+ GF_ASSERT(this);
+@@ -5056,17 +5089,7 @@ glusterd_import_friend_volumes_synctask(void *opaque)
+ if (!arg)
+ goto out;
+
+- peer_data = dict_new();
+- if (!peer_data) {
+- goto out;
+- }
+-
+- ret = dict_unserialize(arg->dict_buf, arg->dictlen, &peer_data);
+- if (ret) {
+- errno = ENOMEM;
+- goto out;
+- }
+-
++ peer_data = arg->peer_data;
+ ret = dict_get_int32n(peer_data, "count", SLEN("count"), &count);
+ if (ret)
+ goto out;
+@@ -5083,11 +5106,18 @@ glusterd_import_friend_volumes_synctask(void *opaque)
+ conf->restart_bricks = _gf_true;
+
+ while (i <= count) {
+- ret = glusterd_import_friend_volume(peer_data, i);
+- if (ret) {
+- break;
++ bm = arg->status_arr[i / 64];
++ while (bm != 0) {
++ /* mask will contain the lowest bit set from bm. */
++ mask = bm & (-bm);
++ bm ^= mask;
++ ret = glusterd_import_friend_volume(peer_data, i + ffsll(mask) - 2,
++ arg);
++ if (ret < 0) {
++ break;
++ }
+ }
+- i++;
++ i += 64;
+ }
+ if (i > count) {
+ glusterd_svcs_manager(NULL);
+@@ -5095,11 +5125,9 @@ glusterd_import_friend_volumes_synctask(void *opaque)
+ conf->restart_bricks = _gf_false;
+ synccond_broadcast(&conf->cond_restart_bricks);
+ out:
+- if (peer_data)
+- dict_unref(peer_data);
+ if (arg) {
+- if (arg->dict_buf)
+- GF_FREE(arg->dict_buf);
++ dict_unref(arg->peer_data);
++ dict_unref(arg->peer_ver_data);
+ GF_FREE(arg);
+ }
+
+@@ -5121,7 +5149,7 @@ glusterd_import_friend_volumes(dict_t *peer_data)
+ goto out;
+
+ while (i <= count) {
+- ret = glusterd_import_friend_volume(peer_data, i);
++ ret = glusterd_import_friend_volume(peer_data, i, NULL);
+ if (ret)
+ goto out;
+ i++;
+@@ -5260,7 +5288,8 @@ out:
+ }
+
+ int32_t
+-glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
++glusterd_compare_friend_data(dict_t *peer_data, dict_t *cmp, int32_t *status,
++ char *hostname)
+ {
+ int32_t ret = -1;
+ int32_t count = 0;
+@@ -5289,8 +5318,19 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
+ if (ret)
+ goto out;
+
++ arg = GF_CALLOC(1, sizeof(*arg) + sizeof(uint64_t) * (count / 64),
++ gf_common_mt_char);
++ if (!arg) {
++ ret = -1;
++ gf_msg("glusterd", GF_LOG_ERROR, ENOMEM, GD_MSG_NO_MEMORY,
++ "Out Of Memory");
++ goto out;
++ }
++ arg->peer_data = dict_ref(peer_data);
++ arg->peer_ver_data = dict_ref(cmp);
+ while (i <= count) {
+- ret = glusterd_compare_friend_volume(peer_data, i, status, hostname);
++ ret = glusterd_compare_friend_volume(peer_data, arg, i, status,
++ hostname);
+ if (ret)
+ goto out;
+
+@@ -5310,21 +5350,13 @@ glusterd_compare_friend_data(dict_t *peer_data, int32_t *status, char *hostname)
+ * first brick to come up before attaching the subsequent bricks
+ * in case brick multiplexing is enabled
+ */
+- arg = GF_CALLOC(1, sizeof(*arg), gf_common_mt_char);
+- ret = dict_allocate_and_serialize(peer_data, &arg->dict_buf,
+- &arg->dictlen);
+- if (ret < 0) {
+- gf_log(this->name, GF_LOG_ERROR,
+- "dict_serialize failed while handling "
+- " import friend volume request");
+- goto out;
+- }
+-
+ glusterd_launch_synctask(glusterd_import_friend_volumes_synctask, arg);
+ }
+
+ out:
+ if (ret && arg) {
++ dict_unref(arg->peer_data);
++ dict_unref(arg->peer_ver_data);
+ GF_FREE(arg);
+ }
+ gf_msg_debug(this->name, 0, "Returning with ret: %d, status: %d", ret,
+diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
+index 5f5de82..02d85d2 100644
+--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
++++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
+@@ -231,7 +231,7 @@ glusterd_add_volumes_to_export_dict(dict_t *peer_data, char **buf,
+ u_int *length);
+
+ int32_t
+-glusterd_compare_friend_data(dict_t *peer_data, int32_t *status,
++glusterd_compare_friend_data(dict_t *peer_data, dict_t *cmp, int32_t *status,
+ char *hostname);
+
+ int
+diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
+index f739b5d..efe4d0e 100644
+--- a/xlators/mgmt/glusterd/src/glusterd.h
++++ b/xlators/mgmt/glusterd/src/glusterd.h
+@@ -234,8 +234,12 @@ typedef struct glusterd_add_dict_args {
+ } glusterd_add_dict_args_t;
+
+ typedef struct glusterd_friend_synctask_args {
+- char *dict_buf;
+- u_int dictlen;
++ dict_t *peer_data;
++ dict_t *peer_ver_data; // Dictionary to save peer version data
++ /* This status_arr[1] is not a real size, real size of the array
++ is dynamically allocated
++ */
++ uint64_t status_arr[1];
+ } glusterd_friend_synctask_args_t;
+
+ typedef enum gf_brick_status {
+--
+1.8.3.1
+