Blob Blame History Raw
From 2f5d6b2923a7f9fe74cf820e5a4cdf894eb0a2bd Mon Sep 17 00:00:00 2001
From: Atin Mukherjee <amukherj@redhat.com>
Date: Thu, 8 Feb 2018 09:09:00 +0530
Subject: [PATCH 147/148] glusterd: import volumes in separate synctask

With brick multiplexing, to attach a brick to an existing brick process
the prerequisite is to have the compatible brick to finish it's
initialization and portmap sign in and hence the thread might have to go
to a sleep and context switch the synctask to allow the brick process to
communicate with glusterd. In normal code path, this works fine as
glusterd_restart_bricks () is launched through a separate synctask.

In case there's a mismatch of the volume when glusterd restarts,
glusterd_import_friend_volume is invoked and then it tries to call
glusterd_start_bricks () from the main thread which eventually may land
into the similar situation. Now since this is not done through a
separate synctask, the 1st brick will never be able to get its turn to
finish all of its handshaking and as a consequence to it, all the bricks
will fail to get attached to it.

Solution : Execute import volume and glusterd restart bricks in separate
synctask. Importing snaps had to be also done through synctask as
there's a dependency of the parent volume need to be available for the
importing snap functionality to work.

>upstream mainline patch : https://review.gluster.org/#/c/19357
                           https://review.gluster.org/#/c/19536/
                           https://review.gluster.org/#/c/19539/

Change-Id: I290b244d456afcc9b913ab30be4af040d340428c
BUG: 1540600
Signed-off-by: Atin Mukherjee <amukherj@redhat.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/129937
Tested-by: RHGS Build Bot <nigelb@redhat.com>
Reviewed-by: Sunil Kumar Heggodu Gopala Acharya <sheggodu@redhat.com>
---
 ...e-with-other-processes-accessing-mounted-path.t |  13 ++
 xlators/mgmt/glusterd/src/glusterd-op-sm.c         |   9 +-
 xlators/mgmt/glusterd/src/glusterd-op-sm.h         |   2 +
 .../mgmt/glusterd/src/glusterd-snapshot-utils.c    | 229 +++++++++++++++++----
 xlators/mgmt/glusterd/src/glusterd-utils.c         | 166 ++++++++++++---
 xlators/mgmt/glusterd/src/glusterd-utils.h         |   4 +
 xlators/mgmt/glusterd/src/glusterd.h               |   3 +-
 7 files changed, 356 insertions(+), 70 deletions(-)

diff --git a/tests/bugs/snapshot/bug-1482023-snpashot-issue-with-other-processes-accessing-mounted-path.t b/tests/bugs/snapshot/bug-1482023-snpashot-issue-with-other-processes-accessing-mounted-path.t
index c5a0088..22f98d2 100644
--- a/tests/bugs/snapshot/bug-1482023-snpashot-issue-with-other-processes-accessing-mounted-path.t
+++ b/tests/bugs/snapshot/bug-1482023-snpashot-issue-with-other-processes-accessing-mounted-path.t
@@ -92,20 +92,33 @@ EXPECT "0" mounted_snaps ${V1}
 # handled during handshake.
 
 activate_snapshots
+
+EXPECT 'Started' snapshot_status ${V0}_snap;
+EXPECT 'Started' snapshot_status ${V1}_snap;
+
 kill_glusterd 2
+
 deactivate_snapshots
+EXPECT 'Stopped' snapshot_status ${V0}_snap;
+EXPECT 'Stopped' snapshot_status ${V1}_snap;
+
 TEST start_glusterd 2
 
 # Updates form friend should reflect as snap was deactivated while glusterd
 # process was inactive and mount point should also not exist.
 
+EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count;
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" mounted_snaps ${V0}
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT "0" mounted_snaps ${V1}
 
 kill_glusterd 2
 activate_snapshots
+EXPECT 'Started' snapshot_status ${V0}_snap;
+EXPECT 'Started' snapshot_status ${V1}_snap;
 TEST start_glusterd 2
 
+EXPECT_WITHIN $PROBE_TIMEOUT 2 peer_count;
+
 # Updates form friend should reflect as snap was activated while glusterd
 # process was inactive and mount point should exist.
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" mounted_snaps ${V0}
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
index 2fc2e3b..81cde21 100644
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
@@ -2426,6 +2426,7 @@ glusterd_stop_bricks (glusterd_volinfo_t *volinfo)
 
 int
 glusterd_start_bricks (glusterd_volinfo_t *volinfo)
+
 {
         int                      ret            = -1;
         glusterd_brickinfo_t    *brickinfo      = NULL;
@@ -2454,14 +2455,6 @@ glusterd_start_bricks (glusterd_volinfo_t *volinfo)
                                 goto out;
                         }
                 }
-
-        }
-        ret = glusterd_store_volinfo (volinfo, GLUSTERD_VOLINFO_VER_AC_NONE);
-        if (ret) {
-                gf_msg (THIS->name, GF_LOG_ERROR, 0, GD_MSG_VOLINFO_STORE_FAIL,
-                        "Failed to write volinfo for volume %s",
-                        volinfo->volname);
-                goto out;
         }
         ret = 0;
 out:
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.h b/xlators/mgmt/glusterd/src/glusterd-op-sm.h
index 48275c5..24b1944 100644
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.h
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.h
@@ -275,8 +275,10 @@ glusterd_volume_stats_write_perf (char *brick_path, int32_t blk_size,
                 int32_t blk_count, double *throughput, double *time);
 gf_boolean_t
 glusterd_is_volume_started (glusterd_volinfo_t  *volinfo);
+
 int
 glusterd_start_bricks (glusterd_volinfo_t *volinfo);
+
 gf_boolean_t
 glusterd_are_all_volumes_stopped ();
 int
diff --git a/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c
index 3f03d2b..ad206f6 100644
--- a/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-snapshot-utils.c
@@ -1758,8 +1758,11 @@ out:
  * 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:
+ * glusterd_compare_snap()  & glusterd_update_snaps () implement the following
+ * algorithm to perform the above task. Please note the former function tries to
+ * iterate over the snaps one at a time and updating the relevant fields in the
+ * dictionary and then glusterd_update_snaps () go over all the snaps and update
+ * them at one go as part of a synctask.
  * Step  1: Start.
  * Step  2: Check if the peer is missing a delete or restore on the said snap.
  *          If yes, goto step 6.
@@ -1784,21 +1787,18 @@ out:
  *
  */
 int32_t
-glusterd_compare_and_update_snap (dict_t *peer_data, int32_t snap_count,
-                                  char *peername, uuid_t peerid)
+glusterd_compare_snap (dict_t *peer_data, int32_t snap_count,
+                       char *peername, uuid_t peerid)
 {
         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;
-        gf_boolean_t      remove_lvm       = _gf_true;
-
         int32_t           ret              = -1;
         int32_t           volcount         = 0;
         xlator_t         *this             = NULL;
@@ -1810,6 +1810,14 @@ glusterd_compare_and_update_snap (dict_t *peer_data, int32_t snap_count,
 
         snprintf (prefix, sizeof(prefix), "snap%d", snap_count);
 
+        ret = dict_set_uint32 (peer_data, buf, 0);
+        snprintf (buf, sizeof(buf), "%s.accept_peer_data", prefix);
+        ret = dict_set_uint32 (peer_data, buf, 0);
+        snprintf (buf, sizeof(buf), "%s.remove_lvm", prefix);
+        ret = dict_set_uint32 (peer_data, buf, 0);
+        snprintf (buf, sizeof(buf), "%s.remove_my_data", prefix);
+        ret = dict_set_uint32 (peer_data, buf, 0);
+
         /* Fetch the peer's snapname */
         snprintf (buf, sizeof(buf), "%s.snapname", prefix);
         ret = dict_get_str (peer_data, buf, &peer_snap_name);
@@ -1866,7 +1874,10 @@ glusterd_compare_and_update_snap (dict_t *peer_data, int32_t snap_count,
                         /* Peer has snap with the same snapname
                         * and snap_id, which local node doesn't have.
                         */
-                        goto accept_peer_data;
+                        snprintf (buf, sizeof(buf), "%s.accept_peer_data",
+                                  prefix);
+                        ret = dict_set_uint32 (peer_data, buf, 1);
+                        goto out;
                 }
                 /* Peer has snap with the same snapname
                  * and snap_id. Now check if peer has a
@@ -1893,12 +1904,18 @@ glusterd_compare_and_update_snap (dict_t *peer_data, int32_t snap_count,
                          * When removing data from local node, make sure
                          * we are not removing backend lvm of the snap.
                          */
-                        remove_lvm = _gf_false;
-                        goto remove_my_data;
+                        snprintf (buf, sizeof(buf), "%s.remove_lvm", prefix);
+                        ret = dict_set_uint32 (peer_data, buf, 0);
+                        snprintf (buf, sizeof(buf), "%s.remove_my_data",
+                                  prefix);
+                        ret = dict_set_uint32 (peer_data, buf, 1);
+                        snprintf (buf, sizeof(buf), "%s.accept_peer_data",
+                                  prefix);
+                        ret = dict_set_uint32 (peer_data, buf, 1);
                 } else {
                         ret = 0;
-                        goto out;
                 }
+                goto out;
         }
 
         /* There is a conflict. Check if the current node is
@@ -1950,50 +1967,176 @@ glusterd_compare_and_update_snap (dict_t *peer_data, int32_t snap_count,
          * And local node isn't. Hence remove local node's
          * data and accept peer data
          */
-
         gf_msg_debug (this->name, 0, "Peer hosts bricks for conflicting "
                 "snap(%s). Removing local data. Accepting peer data.",
                 peer_snap_name);
-        remove_lvm = _gf_true;
+        snprintf (buf, sizeof(buf), "%s.remove_lvm", prefix);
+        ret = dict_set_uint32 (peer_data, buf, 1);
+        snprintf (buf, sizeof(buf), "%s.remove_my_data",
+                  prefix);
+        ret = dict_set_uint32 (peer_data, buf, 1);
+        snprintf (buf, sizeof(buf), "%s.accept_peer_data", prefix);
+        ret = dict_set_uint32 (peer_data, buf, 1);
 
-remove_my_data:
+out:
+        gf_msg_trace (this->name, 0, "Returning %d", ret);
+        return ret;
+}
 
-        dict = dict_new();
-        if (!dict) {
-                gf_msg (this->name, GF_LOG_ERROR, 0,
-                        GD_MSG_DICT_CREATE_FAIL,
-                        "Unable to create dict");
-                ret = -1;
-                goto out;
+int32_t
+glusterd_update_snaps_synctask (void *opaque)
+{
+        int32_t           ret              = -1;
+        int32_t           snap_count       = 0;
+        int               i                = 1;
+        xlator_t         *this             = NULL;
+        dict_t           *peer_data        = NULL;
+        char              buf[NAME_MAX]    = "";
+        char              prefix[NAME_MAX] = "";
+        char             *peer_snap_name   = NULL;
+        char             *peer_snap_id     = NULL;
+        char             *peername         = NULL;
+        gf_boolean_t      remove_lvm       = _gf_false;
+        gf_boolean_t      remove_my_data   = _gf_false;
+        gf_boolean_t      accept_peer_data = _gf_false;
+        int32_t           val              = 0;
+        glusterd_snap_t  *snap             = NULL;
+        dict_t           *dict             = NULL;
+        glusterd_conf_t  *conf             = NULL;
+
+        this = THIS;
+        GF_ASSERT (this);
+
+        conf = this->private;
+        GF_ASSERT (conf);
+
+        peer_data = (dict_t *)opaque;
+        GF_ASSERT (peer_data);
+
+        synclock_lock (&conf->big_lock);
+
+        while (conf->restart_bricks) {
+                synclock_unlock (&conf->big_lock);
+                sleep (2);
+                synclock_lock (&conf->big_lock);
         }
+        conf->restart_bricks = _gf_true;
 
-        ret = glusterd_snap_remove (dict, snap, remove_lvm, _gf_false,
-                                    _gf_false);
+        ret = dict_get_int32 (peer_data, "snap_count", &snap_count);
         if (ret) {
                 gf_msg (this->name, GF_LOG_ERROR, 0,
-                        GD_MSG_SNAP_REMOVE_FAIL,
-                        "Failed to remove snap %s", snap->snapname);
+                        GD_MSG_DICT_GET_FAILED, "Failed to fetch snap_count");
                 goto out;
         }
-
-accept_peer_data:
-
-        /* Accept Peer Data */
-        ret = glusterd_import_friend_snap (peer_data, snap_count,
-                                           peer_snap_name, peer_snap_id);
+        ret = dict_get_str (peer_data, "peername", &peername);
         if (ret) {
                 gf_msg (this->name, GF_LOG_ERROR, 0,
-                        GD_MSG_SNAP_IMPORT_FAIL,
-                        "Failed to import snap %s from peer %s",
-                        peer_snap_name, peername);
+                        GD_MSG_DICT_GET_FAILED, "Failed to fetch peername");
                 goto out;
         }
 
+        for (i = 1; i <= snap_count; i++) {
+                snprintf (prefix, sizeof(prefix), "snap%d", i);
+
+                /* 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_msg (this->name, GF_LOG_ERROR, 0,
+                                GD_MSG_DICT_GET_FAILED,
+                                "Unable to fetch snapname from peer: %s",
+                                peername);
+                        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_msg (this->name, GF_LOG_ERROR, 0,
+                                GD_MSG_DICT_GET_FAILED,
+                                "Unable to fetch snap_id from peer: %s",
+                                peername);
+                        goto out;
+                }
+
+                /* remove_my_data */
+                snprintf (buf, sizeof(buf), "%s.remove_my_data", prefix);
+                ret = dict_get_int32 (peer_data, buf, &val);
+                if (val)
+                        remove_my_data = _gf_true;
+                else
+                        remove_my_data = _gf_false;
+
+                if (remove_my_data) {
+                        snprintf (buf, sizeof(buf), "%s.remove_lvm", prefix);
+                        ret = dict_get_int32 (peer_data, buf, &val);
+                        if (val)
+                                remove_lvm = _gf_true;
+                        else
+                                remove_lvm = _gf_false;
+
+                        dict = dict_new();
+                        if (!dict) {
+                                gf_msg (this->name, GF_LOG_ERROR, 0,
+                                        GD_MSG_DICT_CREATE_FAIL,
+                                        "Unable to create dict");
+                                ret = -1;
+                                goto out;
+                        }
+                        snap = glusterd_find_snap_by_name (peer_snap_name);
+                        if (!snap) {
+                                gf_msg (this->name, GF_LOG_ERROR, 0,
+                                        GD_MSG_MISSED_SNAP_PRESENT,
+                                        "Snapshot %s from peer %s missing on "
+                                        "localhost", peer_snap_name,
+                                        peername);
+                                ret = -1;
+                                goto out;
+                        }
+
+                        ret = glusterd_snap_remove (dict, snap, remove_lvm,
+                                                    _gf_false, _gf_false);
+                        if (ret) {
+                                gf_msg (this->name, GF_LOG_ERROR, 0,
+                                        GD_MSG_SNAP_REMOVE_FAIL,
+                                        "Failed to remove snap %s",
+                                        snap->snapname);
+                                goto out;
+                        }
+                        if (dict)
+                                dict_unref (dict);
+                }
+                snprintf (buf, sizeof(buf), "%s.accept_peer_data", prefix);
+                ret = dict_get_int32 (peer_data, buf, &val);
+                if (val)
+                        accept_peer_data = _gf_true;
+                else
+                        accept_peer_data = _gf_false;
+
+                if (accept_peer_data) {
+                        /* Accept Peer Data */
+                        ret = glusterd_import_friend_snap (peer_data,
+                                                           i,
+                                                           peer_snap_name,
+                                                           peer_snap_id);
+                        if (ret) {
+                                gf_msg (this->name, GF_LOG_ERROR, 0,
+                                        GD_MSG_SNAP_IMPORT_FAIL,
+                                        "Failed to import snap %s from peer %s",
+                                        peer_snap_name, peername);
+                                goto out;
+                        }
+                }
+        }
+
 out:
+        if (peer_data)
+                dict_unref (peer_data);
         if (dict)
                 dict_unref (dict);
+        conf->restart_bricks = _gf_false;
 
-        gf_msg_trace (this->name, 0, "Returning %d", ret);
         return ret;
 }
 
@@ -2008,6 +2151,7 @@ glusterd_compare_friend_snapshots (dict_t *peer_data, char *peername,
         int32_t          snap_count   = 0;
         int              i            = 1;
         xlator_t        *this         = NULL;
+        dict_t          *peer_data_copy = NULL;
 
         this = THIS;
         GF_ASSERT (this);
@@ -2023,8 +2167,7 @@ glusterd_compare_friend_snapshots (dict_t *peer_data, char *peername,
 
         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, peername,
-                                                        peerid);
+                ret = glusterd_compare_snap (peer_data, i, peername, peerid);
                 if (ret) {
                         gf_msg (this->name, GF_LOG_ERROR, 0,
                                 GD_MSG_SNAPSHOT_OP_FAILED,
@@ -2033,6 +2176,18 @@ glusterd_compare_friend_snapshots (dict_t *peer_data, char *peername,
                         goto out;
                 }
         }
+        /* Update the snaps at one go */
+        peer_data_copy = dict_copy_with_ref (peer_data, NULL);
+        ret = dict_set_str (peer_data_copy, "peername", peername);
+        if (ret) {
+                gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
+                        "Failed to set peername into the dict");
+                if (peer_data_copy)
+                        dict_unref (peer_data_copy);
+                goto out;
+        }
+        glusterd_launch_synctask (glusterd_update_snaps_synctask,
+                                  peer_data_copy);
 
 out:
         gf_msg_trace (this->name, 0, "Returning %d", ret);
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index d991a9f..5deacde 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -3448,6 +3448,14 @@ glusterd_compare_friend_volume (dict_t *peer_data, int32_t count,
         *status = GLUSTERD_VOL_COMP_SCS;
 
 out:
+        memset (key, 0, sizeof (key));
+        snprintf (key, sizeof (key), "volume%d.update", count);
+
+        if (*status == GLUSTERD_VOL_COMP_UPDATE_REQ) {
+                ret = dict_set_int32 (peer_data, key, 1);
+        } else {
+                ret = dict_set_int32 (peer_data, key, 0);
+        }
         if (*status == GLUSTERD_VOL_COMP_RJT) {
                 gf_event (EVENT_COMPARE_FRIEND_VOLUME_FAILED, "volume=%s",
                           volinfo->volname);
@@ -3520,12 +3528,11 @@ glusterd_spawn_daemons (void *opaque)
         int             ret     = -1;
 
         synclock_lock (&conf->big_lock);
-        glusterd_restart_bricks (conf);
+        glusterd_restart_bricks ();
         glusterd_restart_gsyncds (conf);
         glusterd_restart_rebalance (conf);
         ret = glusterd_snapdsvc_restart ();
         ret = glusterd_tierdsvc_restart ();
-
         return ret;
 }
 
@@ -4291,20 +4298,35 @@ out:
 int32_t
 glusterd_volume_disconnect_all_bricks (glusterd_volinfo_t *volinfo)
 {
-        int                  ret = 0;
-        glusterd_brickinfo_t *brickinfo = NULL;
+        int                      ret        = 0;
+        glusterd_brickinfo_t    *brickinfo  = NULL;
+        glusterd_brick_proc_t   *brick_proc = NULL;
+        int                      brick_count = 0;
+
         GF_ASSERT (volinfo);
 
         cds_list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) {
                 if (glusterd_is_brick_started (brickinfo)) {
-                        ret = glusterd_brick_disconnect (brickinfo);
-                        if (ret) {
-                                gf_msg ("glusterd", GF_LOG_ERROR, 0,
-                                        GD_MSD_BRICK_DISCONNECT_FAIL,
-                                        "Failed to "
-                                        "disconnect %s:%s", brickinfo->hostname,
-                                        brickinfo->path);
-                                break;
+                        /* If brick multiplexing is enabled then we can't
+                         * blindly set brickinfo->rpc to NULL as it might impact
+                         * the other attached bricks.
+                         */
+                        ret = glusterd_brick_proc_for_port (brickinfo->port,
+                                                            &brick_proc);
+                        if (!ret) {
+                                brick_count = brick_proc->brick_count;
+                        }
+                        if (!is_brick_mx_enabled () || brick_count == 0) {
+                                ret = glusterd_brick_disconnect (brickinfo);
+                                if (ret) {
+                                        gf_msg ("glusterd", GF_LOG_ERROR, 0,
+                                                GD_MSD_BRICK_DISCONNECT_FAIL,
+                                                "Failed to "
+                                                "disconnect %s:%s",
+                                                brickinfo->hostname,
+                                                brickinfo->path);
+                                        break;
+                                }
                         }
                 }
         }
@@ -4543,7 +4565,7 @@ out:
 }
 
 int32_t
-glusterd_import_friend_volume (dict_t *peer_data, size_t count)
+glusterd_import_friend_volume (dict_t *peer_data, int count)
 {
 
         int32_t                 ret = -1;
@@ -4552,6 +4574,8 @@ glusterd_import_friend_volume (dict_t *peer_data, size_t count)
         glusterd_volinfo_t      *old_volinfo = NULL;
         glusterd_volinfo_t      *new_volinfo = NULL;
         glusterd_svc_t          *svc         = NULL;
+        int32_t                  update      = 0;
+        char                     key[512]    = {0,};
 
         GF_ASSERT (peer_data);
 
@@ -4559,6 +4583,15 @@ glusterd_import_friend_volume (dict_t *peer_data, size_t count)
         GF_ASSERT (this);
         priv = this->private;
         GF_ASSERT (priv);
+
+        memset (key, 0, sizeof (key));
+        snprintf (key, sizeof (key), "volume%d.update", count);
+        ret = dict_get_int32 (peer_data, key, &update);
+        if (ret || !update) {
+                /* if update is 0 that means the volume is not imported */
+                goto out;
+        }
+
         ret = glusterd_import_volinfo (peer_data, count,
                                        &new_volinfo, "volume");
         if (ret)
@@ -4572,6 +4605,14 @@ glusterd_import_friend_volume (dict_t *peer_data, size_t count)
 
         ret = glusterd_volinfo_find (new_volinfo->volname, &old_volinfo);
         if (0 == ret) {
+                if (new_volinfo->version <= old_volinfo->version) {
+                        /* When this condition is true, it already means that
+                         * the other synctask thread of import volume has
+                         * already up to date volume, so just ignore this volume
+                         * now
+                         */
+                        goto out;
+                }
                 /* Ref count the old_volinfo such that deleting it doesn't crash
                  * if its been already in use by other thread
                  */
@@ -4602,7 +4643,8 @@ glusterd_import_friend_volume (dict_t *peer_data, size_t count)
                 }
         }
 
-        ret = glusterd_store_volinfo (new_volinfo, GLUSTERD_VOLINFO_VER_AC_NONE);
+        ret = glusterd_store_volinfo (new_volinfo,
+                                      GLUSTERD_VOLINFO_VER_AC_NONE);
         if (ret) {
                 gf_msg (this->name, GF_LOG_ERROR, 0,
                         GD_MSG_VOLINFO_STORE_FAIL, "Failed to store "
@@ -4630,6 +4672,60 @@ out:
 }
 
 int32_t
+glusterd_import_friend_volumes_synctask (void *opaque)
+{
+        int32_t                 ret = -1;
+        int32_t                 count = 0;
+        int                     i = 1;
+        xlator_t                *this = NULL;
+        glusterd_conf_t         *conf = NULL;
+        dict_t *peer_data         = NULL;
+
+        this = THIS;
+        GF_ASSERT (this);
+
+        conf = this->private;
+        GF_ASSERT (conf);
+
+        peer_data = (dict_t *)opaque;
+        GF_ASSERT (peer_data);
+
+        ret = dict_get_int32 (peer_data, "count", &count);
+        if (ret)
+                goto out;
+
+        synclock_lock (&conf->big_lock);
+
+        /* We need to ensure that importing a volume shouldn't race with an
+         * other thread where as part of restarting glusterd, bricks are
+         * restarted (refer glusterd_restart_bricks ())
+         */
+        while (conf->restart_bricks) {
+                synclock_unlock (&conf->big_lock);
+                sleep (2);
+                synclock_lock (&conf->big_lock);
+        }
+        conf->restart_bricks = _gf_true;
+
+        while (i <= count) {
+                ret = glusterd_import_friend_volume (peer_data, i);
+                if (ret) {
+                        conf->restart_bricks = _gf_false;
+                        goto out;
+                }
+                i++;
+        }
+        glusterd_svcs_manager (NULL);
+        conf->restart_bricks = _gf_false;
+out:
+        if (peer_data)
+                dict_unref (peer_data);
+
+        gf_msg_debug ("glusterd", 0, "Returning with %d", ret);
+        return ret;
+}
+
+int32_t
 glusterd_import_friend_volumes (dict_t *peer_data)
 {
         int32_t                 ret = -1;
@@ -4768,8 +4864,10 @@ glusterd_import_global_opts (dict_t *friend_data)
                  * recompute if quorum is met. If quorum is not met bricks are
                  * not started and those already running are stopped
                  */
-                if (old_quorum != new_quorum)
-                        glusterd_restart_bricks (conf);
+                if (old_quorum != new_quorum) {
+                        glusterd_launch_synctask (glusterd_restart_bricks,
+                                                  NULL);
+                }
         }
 
         ret = 0;
@@ -4789,6 +4887,7 @@ glusterd_compare_friend_data (dict_t *peer_data, int32_t *status,
         gf_boolean_t     update    = _gf_false;
         xlator_t        *this      = NULL;
         glusterd_conf_t *priv      = NULL;
+        dict_t          *peer_data_copy = NULL;
 
         this = THIS;
         GF_ASSERT (this);
@@ -4820,18 +4919,23 @@ glusterd_compare_friend_data (dict_t *peer_data, int32_t *status,
                         goto out;
                 }
                 if (GLUSTERD_VOL_COMP_UPDATE_REQ == *status) {
-                        ret = glusterd_import_friend_volume (peer_data, i);
-                        if (ret) {
-                                goto out;
-                        }
                         update = _gf_true;
-                        *status = GLUSTERD_VOL_COMP_NONE;
                 }
                 i++;
         }
 
         if (update) {
-                glusterd_svcs_manager (NULL);
+                /* Launch the import friend volume as a separate synctask as it
+                 * has to trigger start bricks where we may need to wait for the
+                 * first brick to come up before attaching the subsequent bricks
+                 * in case brick multiplexing is enabled
+                 */
+                peer_data_copy = dict_copy_with_ref (peer_data, NULL);
+                glusterd_launch_synctask
+                        (glusterd_import_friend_volumes_synctask,
+                         peer_data_copy);
+                if (ret)
+                        goto out;
         }
 
 out:
@@ -5975,7 +6079,7 @@ out:
 }
 
 int
-glusterd_restart_bricks (glusterd_conf_t *conf)
+glusterd_restart_bricks (void *opaque)
 {
         int                   ret            = 0;
         glusterd_volinfo_t   *volinfo        = NULL;
@@ -5983,6 +6087,7 @@ glusterd_restart_bricks (glusterd_conf_t *conf)
         glusterd_snap_t      *snap           = NULL;
         gf_boolean_t          start_svcs     = _gf_false;
         xlator_t             *this           = NULL;
+        glusterd_conf_t      *conf           = NULL;
         int                   active_count   = 0;
         int                   quorum_count   = 0;
         gf_boolean_t          node_quorum    = _gf_false;
@@ -5993,6 +6098,17 @@ glusterd_restart_bricks (glusterd_conf_t *conf)
         conf = this->private;
         GF_VALIDATE_OR_GOTO (this->name, conf, return_block);
 
+        /* We need to ensure that restarting the bricks during glusterd restart
+         * shouldn't race with the import volume thread (refer
+         * glusterd_compare_friend_data ())
+         */
+        while (conf->restart_bricks) {
+                synclock_unlock (&conf->big_lock);
+                sleep (2);
+                synclock_lock (&conf->big_lock);
+        }
+        conf->restart_bricks = _gf_true;
+
         ++(conf->blockers);
         ret = glusterd_get_quorum_cluster_counts (this, &active_count,
                                                   &quorum_count);
@@ -6003,8 +6119,9 @@ glusterd_restart_bricks (glusterd_conf_t *conf)
                 node_quorum = _gf_true;
 
         cds_list_for_each_entry (volinfo, &conf->volumes, vol_list) {
-                if (volinfo->status != GLUSTERD_STATUS_STARTED)
+                if (volinfo->status != GLUSTERD_STATUS_STARTED) {
                         continue;
+                }
                 gf_msg_debug (this->name, 0, "starting the volume %s",
                         volinfo->volname);
 
@@ -6111,6 +6228,7 @@ glusterd_restart_bricks (glusterd_conf_t *conf)
 out:
         --(conf->blockers);
         conf->restart_done = _gf_true;
+        conf->restart_bricks = _gf_false;
 
 return_block:
         return ret;
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index 9194da0..3b82b1e 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
@@ -245,6 +245,10 @@ glusterd_pending_node_put_rpc (glusterd_pending_node_t *pending_node);
 int
 glusterd_remote_hostname_get (rpcsvc_request_t *req,
                               char *remote_host, int len);
+
+int32_t
+glusterd_import_friend_volumes_synctask (void *opaque);
+
 int32_t
 glusterd_import_friend_volumes (dict_t *peer_data);
 void
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index 3ad5ed6..b0656e6 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -199,6 +199,7 @@ typedef struct {
         int32_t                    workers;
         uint32_t                   blockers;
         uint32_t                   mgmt_v3_lock_timeout;
+        gf_boolean_t               restart_bricks;
 } glusterd_conf_t;
 
 
@@ -1077,7 +1078,7 @@ glusterd_add_volume_detail_to_dict (glusterd_volinfo_t *volinfo,
                                     dict_t  *volumes, int   count);
 
 int
-glusterd_restart_bricks (glusterd_conf_t *conf);
+glusterd_restart_bricks ();
 
 int32_t
 glusterd_volume_txn (rpcsvc_request_t *req, char *volname, int flags,
-- 
1.8.3.1