3604df
From 220e093d7838493d2f88c77ebda18d277b21a4d9 Mon Sep 17 00:00:00 2001
3604df
From: karthik-us <ksubrahm@redhat.com>
3604df
Date: Thu, 5 Jan 2017 14:06:21 +0530
3604df
Subject: [PATCH 266/267] glusterd: Fail add-brick on replica count change, if
3604df
 brick is down
3604df
3604df
Problem:
3604df
1. Have a replica 2 volume with bricks b1 and b2
3604df
2. Before setting the layout, b1 goes down
3604df
3. Set the layout write some data, which gets populated on b2
3604df
4. b2 goes down then b1 comes up
3604df
5. Add another brick b3, and heal will take place from b1 to b3, which
3604df
   basically have no data
3604df
6. Write some data. Both b1 and b3 will mark b2 for pending writes
3604df
7. b1 goes down, and b2 comes up
3604df
8. b2 gets heald from b1. During heal it removes the data which is already
3604df
   in b2, considering that as stale data. This leads to data loss.
3604df
3604df
Solution:
3604df
1. In glusterd stage-op, while adding bricks, check whether the replica
3604df
   count is being increased
3604df
2. If yes, then check whether any of the bricks are down at that time
3604df
3. If yes, then fail the add-brick to avoid such data loss
3604df
4. Else continue the normal operation.
3604df
3604df
This check will work enen when we convert plain distribute volume to replicate
3604df
3604df
Test:
3604df
1. Create a replica 2 volume
3604df
2. Kill one brick from the volume
3604df
3. Try adding a brick to the volume
3604df
4. It should fail with all bricks are not up error
3604df
5. Cretae a distribute volume and kill one of the brick
3604df
6. Try to convert it to replicate volume, by adding bricks.
3604df
7. This should also fail.
3604df
3604df
>Reviewed-on: http://review.gluster.org/16330
3604df
>Tested-by: Ravishankar N <ravishankar@redhat.com>
3604df
>Smoke: Gluster Build System <jenkins@build.gluster.org>
3604df
>NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
3604df
>Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
3604df
>CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
3604df
>Reviewed-by: N Balachandran <nbalacha@redhat.com>
3604df
>Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
3604df
3604df
Change-Id: I9c8d2ab104263e4206814c94c19212ab914ed07c
3604df
BUG: 1404989
3604df
Signed-off-by: karthik-us <ksubrahm@redhat.com>
3604df
Reviewed-on: https://code.engineering.redhat.com/gerrit/94355
3604df
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
3604df
Tested-by: Atin Mukherjee <amukherj@redhat.com>
3604df
---
3604df
 tests/basic/afr/arbiter-add-brick.t                | 10 ++++--
3604df
 ...406411-fail-add-brick-on-replica-count-change.t | 40 ++++++++++++++++++++++
3604df
 xlators/mgmt/glusterd/src/glusterd-brick-ops.c     | 19 ++++++++++
3604df
 3 files changed, 66 insertions(+), 3 deletions(-)
3604df
 create mode 100644 tests/bugs/glusterd/bug-1406411-fail-add-brick-on-replica-count-change.t
3604df
3604df
diff --git a/tests/basic/afr/arbiter-add-brick.t b/tests/basic/afr/arbiter-add-brick.t
3604df
index 357f59b..69e1326 100644
3604df
--- a/tests/basic/afr/arbiter-add-brick.t
3604df
+++ b/tests/basic/afr/arbiter-add-brick.t
3604df
@@ -10,6 +10,7 @@ TEST pidof glusterd
3604df
 TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
3604df
 TEST $CLI volume set $V0 performance.stat-prefetch off
3604df
 TEST $CLI volume start $V0
3604df
+TEST $CLI volume set $V0 self-heal-daemon off
3604df
 TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 $M0;
3604df
 TEST mkdir  $M0/dir1
3604df
 TEST dd if=/dev/urandom of=$M0/file1 bs=1024 count=1
3604df
@@ -20,21 +21,24 @@ TEST mkdir $M0/dir2
3604df
 TEST dd if=/dev/urandom of=$M0/file1 bs=1024 count=1024
3604df
 
3604df
 
3604df
+#convert replica 2 to arbiter volume
3604df
+TEST $CLI volume start $V0 force
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1
3604df
+
3604df
 #syntax check for add-brick.
3604df
 TEST ! $CLI volume add-brick $V0 replica 2 arbiter 1 $H0:$B0/${V0}2
3604df
 TEST ! $CLI volume add-brick $V0 replica 3 arbiter 2 $H0:$B0/${V0}2
3604df
 
3604df
-#convert replica 2 to arbiter volume
3604df
 TEST $CLI volume add-brick $V0 replica 3 arbiter 1 $H0:$B0/${V0}2
3604df
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2
3604df
 
3604df
 #Heal files
3604df
-TEST $CLI volume start $V0 force
3604df
-EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1
3604df
+TEST $CLI volume set $V0 self-heal-daemon on
3604df
 EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
3604df
 EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
3604df
 EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
3604df
 EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2
3604df
+TEST $CLI volume heal $V0
3604df
 EXPECT_WITHIN $HEAL_TIMEOUT "0" get_pending_heal_count $V0
3604df
 
3604df
 #Perform I/O after add-brick
3604df
diff --git a/tests/bugs/glusterd/bug-1406411-fail-add-brick-on-replica-count-change.t b/tests/bugs/glusterd/bug-1406411-fail-add-brick-on-replica-count-change.t
3604df
new file mode 100644
3604df
index 0000000..bbd2d4c
3604df
--- /dev/null
3604df
+++ b/tests/bugs/glusterd/bug-1406411-fail-add-brick-on-replica-count-change.t
3604df
@@ -0,0 +1,40 @@
3604df
+#!/bin/bash
3604df
+
3604df
+. $(dirname $0)/../../include.rc
3604df
+. $(dirname $0)/../../volume.rc
3604df
+
3604df
+cleanup;
3604df
+
3604df
+TEST glusterd;
3604df
+TEST pidof glusterd
3604df
+
3604df
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2};
3604df
+TEST $CLI volume start $V0
3604df
+
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2
3604df
+TEST kill_brick $V0 $H0 $B0/${V0}1
3604df
+
3604df
+#add-brick should fail
3604df
+TEST ! $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}3
3604df
+
3604df
+TEST $CLI volume start $V0 force
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}1
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V0 $H0 $B0/${V0}2
3604df
+TEST $CLI volume add-brick $V0 replica 3 $H0:$B0/${V0}3
3604df
+
3604df
+TEST $CLI volume create $V1 $H0:$B0/${V1}{1,2};
3604df
+TEST $CLI volume start $V1
3604df
+
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V1 $H0 $B0/${V1}1
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V1 $H0 $B0/${V1}2
3604df
+TEST kill_brick $V1 $H0 $B0/${V1}1
3604df
+
3604df
+#add-brick should fail
3604df
+TEST ! $CLI volume add-brick $V1 replica 2 $H0:$B0/${V1}{3,4}
3604df
+
3604df
+TEST $CLI volume start $V1 force
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V1 $H0 $B0/${V1}1
3604df
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" brick_up_status $V1 $H0 $B0/${V1}2
3604df
+TEST $CLI volume add-brick $V1 replica 2 $H0:$B0/${V1}{3,4}
3604df
+cleanup;
3604df
diff --git a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
3604df
index 5791e98..bd6025d 100644
3604df
--- a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
3604df
+++ b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c
3604df
@@ -1724,6 +1724,25 @@ glusterd_op_stage_add_brick (dict_t *dict, char **op_errstr, dict_t *rsp_dict)
3604df
                 }
3604df
         }
3604df
 
3604df
+        if (volinfo->replica_count < replica_count) {
3604df
+                cds_list_for_each_entry (brickinfo, &volinfo->bricks,
3604df
+                                         brick_list) {
3604df
+                        if (gf_uuid_compare (brickinfo->uuid, MY_UUID))
3604df
+                                continue;
3604df
+                        if (brickinfo->status == GF_BRICK_STOPPED) {
3604df
+                                ret = -1;
3604df
+                                snprintf (msg, sizeof (msg), "Brick %s is down,"
3604df
+                                          " changing replica count needs all "
3604df
+                                          "the bricks to be up to avoid data "
3604df
+                                          "loss", brickinfo->path);
3604df
+                                gf_msg (THIS->name, GF_LOG_ERROR, 0,
3604df
+                                        GD_MSG_BRICK_ADD_FAIL, "%s", msg);
3604df
+                                *op_errstr = gf_strdup (msg);
3604df
+                                goto out;
3604df
+                        }
3604df
+                }
3604df
+        }
3604df
+
3604df
         if (conf->op_version > GD_OP_VERSION_3_7_5 &&
3604df
             is_origin_glusterd (dict)) {
3604df
                 ret = glusterd_validate_quorum (this, GD_OP_ADD_BRICK, dict,
3604df
-- 
3604df
2.9.3
3604df