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