21ab4e
From 4546cfb8bd7e9b42c01803a543fa52471574265d Mon Sep 17 00:00:00 2001
21ab4e
From: Mohit Agrawal <moagrawa@redhat.com>
21ab4e
Date: Fri, 19 Aug 2016 10:33:50 +0530
21ab4e
Subject: [PATCH 306/361] dht: "replica.split-brain-status" attribute value is
21ab4e
 not correct
21ab4e
21ab4e
Problem: In a distributed-replicate volume attribute
21ab4e
         "replica.split-brain-status" value does not display split-brain
21ab4e
           condition though directory is in split-brain.
21ab4e
         If directory is in split brain on mutiple replica-pairs
21ab4e
         it does not show full list of replica pairs.
21ab4e
21ab4e
Solution: Update the dht_aggregate code to aggregate the xattr
21ab4e
          value in this specific condition.
21ab4e
21ab4e
Fix:      1) function getChoices returns the choices from split-brain
21ab4e
             status string.
21ab4e
          2) function add_opt adding the choices to local buffer to
21ab4e
             store in dictionary
21ab4e
          3) For the key "replica.split-brain-status" function dht_aggregate
21ab4e
             call dht_aggregate_split_brain_xattr to prepare the list.
21ab4e
21ab4e
Test:     To verify the patch followed below steps
21ab4e
          1) Create a distributed replica volume and create mount point
21ab4e
          2) Stop heal daemon
21ab4e
          3) Touch file and directories on mount point
21ab4e
             mkdir test{1..5};touch tmp{1..5}
21ab4e
          4) Down brick process on one of the replica set
21ab4e
             pkill -9 glusterfsd
21ab4e
          5) Change permission of dir on mount point
21ab4e
             chmod 755 test{1..5}
21ab4e
          6) Restart brick process on node with force option
21ab4e
          7) kill brick process on other node in same replica set
21ab4e
          8) Change permission of dir again on mount point
21ab4e
             chmod 766 test{1..5}
21ab4e
          9) Reexecute same step from 4-9 on other replica set also
21ab4e
          10) After check heal status on server it will show dir's are
21ab4e
              in split brain on all replica sets
21ab4e
          11) After check the replica.split-brain-status attr on mount
21ab4e
              point it will show wrong status of split brain.
21ab4e
          12) After apply the patch the attribute shows correct value.
21ab4e
21ab4e
mainline:
21ab4e
> BUG: 1368312
21ab4e
> Reviewed-on: http://review.gluster.org/15201
21ab4e
> Smoke: Gluster Build System <jenkins@build.gluster.org>
21ab4e
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
21ab4e
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
21ab4e
> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
21ab4e
(cherry picked from commit 975932767d8131e8c331ea3eb527bd8b7240976d)
21ab4e
21ab4e
BUG: 1260779
21ab4e
Change-Id: Icdfd72005a4aa82337c342762775a3d1761bbe4a
21ab4e
Signed-off-by: Mohit Agrawal <moagrawa@redhat.com>
21ab4e
Reviewed-on: https://code.engineering.redhat.com/gerrit/101282
21ab4e
Tested-by: Milind Changire <mchangir@redhat.com>
21ab4e
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
21ab4e
---
21ab4e
 tests/bugs/bug-1368312.t             |  84 ++++++++++++++
21ab4e
 xlators/cluster/dht/src/dht-common.c | 212 +++++++++++++++++++++++++++++++++--
21ab4e
 xlators/cluster/dht/src/dht-common.h |   9 ++
21ab4e
 3 files changed, 293 insertions(+), 12 deletions(-)
21ab4e
 create mode 100644 tests/bugs/bug-1368312.t
21ab4e
21ab4e
diff --git a/tests/bugs/bug-1368312.t b/tests/bugs/bug-1368312.t
21ab4e
new file mode 100644
21ab4e
index 0000000..135048f
21ab4e
--- /dev/null
21ab4e
+++ b/tests/bugs/bug-1368312.t
21ab4e
@@ -0,0 +1,84 @@
21ab4e
+#!/bin/bash
21ab4e
+. $(dirname $0)/../include.rc
21ab4e
+. $(dirname $0)/../volume.rc
21ab4e
+cleanup;
21ab4e
+
21ab4e
+function compare_get_split_brain_status {
21ab4e
+        local path=$1
21ab4e
+        local choice=$2
21ab4e
+        echo `getfattr -n replica.split-brain-status $path` | cut -f2 -d"=" | sed -e 's/^"//'  -e 's/"$//' | grep $choice
21ab4e
+        if [ $? -ne 0 ]
21ab4e
+        then
21ab4e
+                echo 1
21ab4e
+        else
21ab4e
+                echo 0
21ab4e
+        fi
21ab4e
+
21ab4e
+}
21ab4e
+
21ab4e
+TEST glusterd
21ab4e
+TEST pidof glusterd
21ab4e
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3,4,5}
21ab4e
+TEST $CLI volume start $V0
21ab4e
+
21ab4e
+#Disable self-heal-daemon
21ab4e
+TEST $CLI volume set $V0 cluster.self-heal-daemon off
21ab4e
+
21ab4e
+TEST glusterfs --volfile-id=$V0 --volfile-server=$H0 --entry-timeout=0 $M0;
21ab4e
+
21ab4e
+TEST mkdir $M0/tmp1
21ab4e
+
21ab4e
+#Create metadata split-brain
21ab4e
+TEST kill_brick $V0 $H0 $B0/${V0}0
21ab4e
+TEST chmod 666 $M0/tmp1
21ab4e
+TEST $CLI volume start $V0 force
21ab4e
+TEST kill_brick $V0 $H0 $B0/${V0}1
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
21ab4e
+
21ab4e
+TEST chmod 757 $M0/tmp1
21ab4e
+
21ab4e
+TEST $CLI volume start $V0 force
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
21ab4e
+
21ab4e
+EXPECT 2 get_pending_heal_count $V0
21ab4e
+
21ab4e
+
21ab4e
+TEST kill_brick $V0 $H0 $B0/${V0}2
21ab4e
+TEST chmod 755 $M0/tmp1
21ab4e
+TEST $CLI volume start $V0 force
21ab4e
+TEST kill_brick $V0 $H0 $B0/${V0}3
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
21ab4e
+
21ab4e
+TEST chmod 766 $M0/tmp1
21ab4e
+
21ab4e
+TEST $CLI volume start $V0 force
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 3
21ab4e
+
21ab4e
+EXPECT 4 get_pending_heal_count $V0
21ab4e
+
21ab4e
+TEST kill_brick $V0 $H0 $B0/${V0}4
21ab4e
+TEST chmod 765 $M0/tmp1
21ab4e
+TEST $CLI volume start $V0 force
21ab4e
+TEST kill_brick $V0 $H0 $B0/${V0}5
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 4
21ab4e
+
21ab4e
+TEST chmod 756 $M0/tmp1
21ab4e
+
21ab4e
+TEST $CLI volume start $V0 force
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 4
21ab4e
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 5
21ab4e
+
21ab4e
+EXPECT 6 get_pending_heal_count $V0
21ab4e
+
21ab4e
+cd $M0
21ab4e
+EXPECT 0 compare_get_split_brain_status ./tmp1 patchy-client-0
21ab4e
+EXPECT 0 compare_get_split_brain_status ./tmp1 patchy-client-1
21ab4e
+EXPECT 0 compare_get_split_brain_status ./tmp1 patchy-client-2
21ab4e
+EXPECT 0 compare_get_split_brain_status ./tmp1 patchy-client-3
21ab4e
+EXPECT 0 compare_get_split_brain_status ./tmp1 patchy-client-4
21ab4e
+EXPECT 0 compare_get_split_brain_status ./tmp1 patchy-client-5
21ab4e
+
21ab4e
+cd -
21ab4e
+cleanup
21ab4e
diff --git a/xlators/cluster/dht/src/dht-common.c b/xlators/cluster/dht/src/dht-common.c
21ab4e
index 62657a0..4907931 100644
21ab4e
--- a/xlators/cluster/dht/src/dht-common.c
21ab4e
+++ b/xlators/cluster/dht/src/dht-common.c
21ab4e
@@ -127,6 +127,190 @@ out:
21ab4e
 }
21ab4e
 
21ab4e
 
21ab4e
+int add_opt(char **optsp, const char *opt)
21ab4e
+{
21ab4e
+        char *newopts = NULL;
21ab4e
+        unsigned oldsize = 0;
21ab4e
+        unsigned newsize = 0;
21ab4e
+
21ab4e
+        if (*optsp == NULL)
21ab4e
+                newopts = gf_strdup (opt);
21ab4e
+        else {
21ab4e
+                oldsize = strlen (*optsp);
21ab4e
+                newsize = oldsize + 1 + strlen (opt) + 1;
21ab4e
+                newopts = GF_REALLOC (*optsp, newsize);
21ab4e
+                if (newopts)
21ab4e
+                        sprintf (newopts + oldsize, ",%s", opt);
21ab4e
+        }
21ab4e
+        if (newopts == NULL) {
21ab4e
+                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                        DHT_MSG_NO_MEMORY,
21ab4e
+                        "Error to add choices in buffer in add_opt");
21ab4e
+                return -1;
21ab4e
+        }
21ab4e
+        *optsp = newopts;
21ab4e
+        return 0;
21ab4e
+}
21ab4e
+
21ab4e
+/* Return Choice list from Split brain status */
21ab4e
+char *
21ab4e
+getChoices (const char *value)
21ab4e
+{
21ab4e
+        int i = 0;
21ab4e
+        char *ptr = NULL;
21ab4e
+        char *tok = NULL;
21ab4e
+        char *result = NULL;
21ab4e
+        char *newval = NULL;
21ab4e
+
21ab4e
+        ptr = strstr (value, "Choices:");
21ab4e
+        if (!ptr) {
21ab4e
+                result = ptr;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        newval = gf_strdup (ptr);
21ab4e
+        if (!newval) {
21ab4e
+                result = newval;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        tok = strtok (newval, ":");
21ab4e
+        if (!tok) {
21ab4e
+                result = tok;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        while (tok) {
21ab4e
+                i++;
21ab4e
+                if (i == 2)
21ab4e
+                        break;
21ab4e
+                tok = strtok (NULL, ":");
21ab4e
+        }
21ab4e
+
21ab4e
+        result = gf_strdup (tok);
21ab4e
+
21ab4e
+out:
21ab4e
+        if (newval)
21ab4e
+                GF_FREE (newval);
21ab4e
+
21ab4e
+        return result;
21ab4e
+}
21ab4e
+
21ab4e
+/* This function prepare a list of choices for key
21ab4e
+   (replica.split-brain-status) in   case of metadata split brain
21ab4e
+   only on the basis of key-value passed to this function.
21ab4e
+   After prepare the list of choices it update the same key in dict
21ab4e
+   with this value to reflect the same in
21ab4e
+   replica.split-brain-status attr for file.
21ab4e
+
21ab4e
+*/
21ab4e
+
21ab4e
+int
21ab4e
+dht_aggregate_split_brain_xattr (dict_t *dst, char *key, data_t *value)
21ab4e
+{
21ab4e
+
21ab4e
+        int              ret            = 0;
21ab4e
+        char            *oldvalue       = NULL;
21ab4e
+        char            *old_choice     = NULL;
21ab4e
+        char            *new_choice     = NULL;
21ab4e
+        char            *full_choice    = NULL;
21ab4e
+        char            *status         = NULL;
21ab4e
+
21ab4e
+        if (value == NULL) {
21ab4e
+                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                        DHT_MSG_DATA_NULL,
21ab4e
+                        "GF_AFR_SBRAIN_STATUS value is NULL");
21ab4e
+                ret = -1;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+
21ab4e
+        ret = dict_get_str (dst, key, &oldvalue);
21ab4e
+        if (ret)
21ab4e
+                goto out;
21ab4e
+
21ab4e
+        if (oldvalue && (strstr (oldvalue, "not"))) {
21ab4e
+                gf_msg_debug ("dht", 0,
21ab4e
+                              "Need to update split-brain status in dict");
21ab4e
+                ret = -1;
21ab4e
+                goto out;
21ab4e
+        }
21ab4e
+        if (oldvalue && (strstr (oldvalue, "metadata-split-brain:yes"))
21ab4e
+                     && (strstr (oldvalue, "data-split-brain:no"))) {
21ab4e
+                if (strstr (value->data, "not")) {
21ab4e
+                        gf_msg_debug ("dht", 0,
21ab4e
+                                      "No need to update split-brain status");
21ab4e
+                        ret = 0;
21ab4e
+                        goto out;
21ab4e
+                }
21ab4e
+                if (strstr (value->data, "yes") &&
21ab4e
+                        (strncmp (oldvalue, value->data, strlen(oldvalue)))) {
21ab4e
+                        old_choice = getChoices (oldvalue);
21ab4e
+                        if (!old_choice) {
21ab4e
+                                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                                        DHT_MSG_NO_MEMORY,
21ab4e
+                                        "Error to get choices");
21ab4e
+                                ret = -1;
21ab4e
+                                goto out;
21ab4e
+                        }
21ab4e
+
21ab4e
+                        ret = add_opt (&full_choice, old_choice);
21ab4e
+                        if (ret) {
21ab4e
+                                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                                         DHT_MSG_NO_MEMORY,
21ab4e
+                                         "Error to add choices");
21ab4e
+                                ret = -1;
21ab4e
+                                goto out;
21ab4e
+                        }
21ab4e
+
21ab4e
+                        new_choice = getChoices (value->data);
21ab4e
+                        if (!new_choice) {
21ab4e
+                                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                                        DHT_MSG_NO_MEMORY,
21ab4e
+                                        "Error to get choices");
21ab4e
+                                ret = -1;
21ab4e
+                                goto out;
21ab4e
+                        }
21ab4e
+
21ab4e
+                        ret = add_opt (&full_choice, new_choice);
21ab4e
+                        if (ret) {
21ab4e
+                                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                                       DHT_MSG_NO_MEMORY,
21ab4e
+                                       "Error to add choices ");
21ab4e
+                                ret = -1;
21ab4e
+                                goto out;
21ab4e
+                        }
21ab4e
+                        ret = gf_asprintf (&status,
21ab4e
+                                           "data-split-brain:%s    "
21ab4e
+                                           "metadata-split-brain:%s   Choices:%s",
21ab4e
+                                           "no", "yes", full_choice);
21ab4e
+
21ab4e
+                        if (-1 == ret) {
21ab4e
+                                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                                                 DHT_MSG_NO_MEMORY,
21ab4e
+                                                "Error to prepare status ");
21ab4e
+                                        goto out;
21ab4e
+                                }
21ab4e
+                        ret = dict_set_dynstr (dst, key, status);
21ab4e
+                        if (ret) {
21ab4e
+                                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                                        DHT_MSG_DICT_SET_FAILED,
21ab4e
+                                        "Failed to set full choice");
21ab4e
+                        }
21ab4e
+                }
21ab4e
+        }
21ab4e
+
21ab4e
+out:
21ab4e
+        if (old_choice)
21ab4e
+                GF_FREE (old_choice);
21ab4e
+        if (new_choice)
21ab4e
+                GF_FREE (new_choice);
21ab4e
+        if (full_choice)
21ab4e
+                GF_FREE (full_choice);
21ab4e
+
21ab4e
+        return ret;
21ab4e
+}
21ab4e
+
21ab4e
+
21ab4e
 
21ab4e
 int
21ab4e
 dht_aggregate (dict_t *this, char *key, data_t *value, void *data)
21ab4e
@@ -137,18 +321,22 @@ dht_aggregate (dict_t *this, char *key, data_t *value, void *data)
21ab4e
 
21ab4e
         dst = data;
21ab4e
 
21ab4e
-        if (strcmp (key, QUOTA_SIZE_KEY) == 0) {
21ab4e
+        /* compare split brain xattr only */
21ab4e
+        if (strcmp (key, GF_AFR_SBRAIN_STATUS) == 0) {
21ab4e
+                ret = dht_aggregate_split_brain_xattr(dst, key, value);
21ab4e
+                if (!ret)
21ab4e
+                        goto out;
21ab4e
+        } else if (strcmp (key, QUOTA_SIZE_KEY) == 0) {
21ab4e
                 ret = dht_aggregate_quota_xattr (dst, key, value);
21ab4e
                 if (ret) {
21ab4e
                         gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
                                 DHT_MSG_AGGREGATE_QUOTA_XATTR_FAILED,
21ab4e
                                 "Failed to aggregate quota xattr");
21ab4e
-                        goto out;
21ab4e
                 }
21ab4e
+                goto out;
21ab4e
         } else if (fnmatch (GF_XATTR_STIME_PATTERN, key, FNM_NOESCAPE) == 0) {
21ab4e
                 ret = gf_get_min_stime (THIS, dst, key, value);
21ab4e
-                if (ret < 0)
21ab4e
-                        goto out;
21ab4e
+                goto out;
21ab4e
         } else {
21ab4e
                 /* compare user xattrs only */
21ab4e
                 if (!strncmp (key, "user.", strlen ("user."))) {
21ab4e
@@ -161,16 +349,16 @@ dht_aggregate (dict_t *this, char *key, data_t *value, void *data)
21ab4e
                                                       key);
21ab4e
                         }
21ab4e
                 }
21ab4e
-                ret = dict_set (dst, key, value);
21ab4e
-                if (ret) {
21ab4e
-                        gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
-                                DHT_MSG_DICT_SET_FAILED,
21ab4e
-                                "Failed to set dictionary value: key = %s",
21ab4e
-                                key);
21ab4e
-                }
21ab4e
         }
21ab4e
 
21ab4e
-        ret = 0;
21ab4e
+        ret = dict_set (dst, key, value);
21ab4e
+        if (ret) {
21ab4e
+                gf_msg ("dht", GF_LOG_WARNING, 0,
21ab4e
+                        DHT_MSG_DICT_SET_FAILED,
21ab4e
+                        "Failed to set dictionary value: key = %s",
21ab4e
+                        key);
21ab4e
+        }
21ab4e
+
21ab4e
 out:
21ab4e
         return ret;
21ab4e
 }
21ab4e
diff --git a/xlators/cluster/dht/src/dht-common.h b/xlators/cluster/dht/src/dht-common.h
21ab4e
index e87bd90..21e000a 100644
21ab4e
--- a/xlators/cluster/dht/src/dht-common.h
21ab4e
+++ b/xlators/cluster/dht/src/dht-common.h
21ab4e
@@ -1236,4 +1236,13 @@ dht_get_lock_subvolume (xlator_t *this, struct gf_flock *lock,
21ab4e
 int
21ab4e
 dht_lk_inode_unref (call_frame_t *frame, int32_t op_ret);
21ab4e
 
21ab4e
+int
21ab4e
+add_opt(char **optsp, const char *opt);
21ab4e
+
21ab4e
+char *
21ab4e
+getChoices (const char *value);
21ab4e
+
21ab4e
+int
21ab4e
+dht_aggregate_split_brain_xattr (dict_t *dst, char *key, data_t *value);
21ab4e
+
21ab4e
 #endif/* _DHT_H */
21ab4e
-- 
21ab4e
1.8.3.1
21ab4e