74096c
From 708c17a8a69b2657f384affaedfcf4ba0a123893 Mon Sep 17 00:00:00 2001
74096c
From: karthik-us <ksubrahm@redhat.com>
74096c
Date: Wed, 23 Dec 2020 14:45:07 +0530
74096c
Subject: [PATCH 513/517] afr: mark pending xattrs as a part of metadata heal
74096c
74096c
...if pending xattrs are zero for all children.
74096c
74096c
Problem:
74096c
If there are no pending xattrs and a metadata heal needs to be
74096c
performed, it can be possible that we end up with xattrs inadvertendly
74096c
deleted from all bricks, as explained in the  BZ.
74096c
74096c
Fix:
74096c
After picking one among the sources as the good copy, mark pending xattrs on
74096c
all sources to blame the sinks. Now even if this metadata heal fails midway,
74096c
a subsequent heal will still choose one of the valid sources that it
74096c
picked previously.
74096c
74096c
Upstream patch details:
74096c
> Fixes: #1067
74096c
> Change-Id: If1b050b70b0ad911e162c04db4d89b263e2b8d7b
74096c
> Signed-off-by: Ravishankar N <ravishankar@redhat.com>
74096c
Upstream patch: https://review.gluster.org/#/c/glusterfs/+/21922/
74096c
74096c
BUG: 1640148
74096c
Change-Id: If1b050b70b0ad911e162c04db4d89b263e2b8d7b
74096c
Signed-off-by: karthik-us <ksubrahm@redhat.com>
74096c
Reviewed-on: https://code.engineering.redhat.com/gerrit/222073
74096c
Tested-by: RHGS Build Bot <nigelb@redhat.com>
74096c
Reviewed-by: Ravishankar Narayanankutty <ravishankar@redhat.com>
74096c
---
74096c
 tests/bugs/replicate/mdata-heal-no-xattrs.t      | 59 ++++++++++++++++++++++
74096c
 xlators/cluster/afr/src/afr-self-heal-metadata.c | 62 +++++++++++++++++++++++-
74096c
 2 files changed, 120 insertions(+), 1 deletion(-)
74096c
 create mode 100644 tests/bugs/replicate/mdata-heal-no-xattrs.t
74096c
74096c
diff --git a/tests/bugs/replicate/mdata-heal-no-xattrs.t b/tests/bugs/replicate/mdata-heal-no-xattrs.t
74096c
new file mode 100644
74096c
index 0000000..d3b0c50
74096c
--- /dev/null
74096c
+++ b/tests/bugs/replicate/mdata-heal-no-xattrs.t
74096c
@@ -0,0 +1,59 @@
74096c
+#!/bin/bash
74096c
+
74096c
+. $(dirname $0)/../../include.rc
74096c
+. $(dirname $0)/../../volume.rc
74096c
+cleanup;
74096c
+
74096c
+TEST glusterd
74096c
+TEST pidof glusterd
74096c
+TEST $CLI volume create $V0 replica 3 $H0:$B0/${V0}{0,1,2};
74096c
+TEST $CLI volume set $V0 cluster.self-heal-daemon off
74096c
+TEST $CLI volume start $V0
74096c
+
74096c
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0
74096c
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
74096c
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
74096c
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
74096c
+echo "Data">$M0/FILE
74096c
+ret=$?
74096c
+TEST [ $ret -eq 0 ]
74096c
+
74096c
+# Change permission on brick-0: simulates the case where there is metadata
74096c
+# mismatch but no pending xattrs. This brick will become the source for heal.
74096c
+TEST chmod +x $B0/$V0"0"/FILE
74096c
+
74096c
+# Add gfid to xattrop
74096c
+xattrop_b0=$(afr_get_index_path $B0/$V0"0")
74096c
+base_entry_b0=`ls $xattrop_b0`
74096c
+gfid_str_FILE=$(gf_gfid_xattr_to_str $(gf_get_gfid_xattr $B0/$V0"0"/FILE))
74096c
+TEST ln $xattrop_b0/$base_entry_b0 $xattrop_b0/$gfid_str_FILE
74096c
+EXPECT_WITHIN $HEAL_TIMEOUT "^1$" get_pending_heal_count $V0
74096c
+
74096c
+TEST $CLI volume set $V0 cluster.self-heal-daemon on
74096c
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 0
74096c
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 1
74096c
+EXPECT_WITHIN $CHILD_UP_TIMEOUT "1" afr_child_up_status_in_shd $V0 2
74096c
+TEST $CLI volume heal $V0
74096c
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" get_pending_heal_count $V0
74096c
+
74096c
+# Brick-0 should contain xattrs blaming other 2 bricks.
74096c
+# The values will be zero because heal is over.
74096c
+EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-1 $B0/${V0}0/FILE
74096c
+EXPECT "000000000000000000000000" get_hex_xattr trusted.afr.$V0-client-2 $B0/${V0}0/FILE
74096c
+TEST ! getfattr -n trusted.afr.$V0-client-0 $B0/${V0}0/FILE
74096c
+
74096c
+# Brick-1 and Brick-2 must not contain any afr xattrs.
74096c
+TEST ! getfattr -n trusted.afr.$V0-client-0 $B0/${V0}1/FILE
74096c
+TEST ! getfattr -n trusted.afr.$V0-client-1 $B0/${V0}1/FILE
74096c
+TEST ! getfattr -n trusted.afr.$V0-client-2 $B0/${V0}1/FILE
74096c
+TEST ! getfattr -n trusted.afr.$V0-client-0 $B0/${V0}2/FILE
74096c
+TEST ! getfattr -n trusted.afr.$V0-client-1 $B0/${V0}2/FILE
74096c
+TEST ! getfattr -n trusted.afr.$V0-client-2 $B0/${V0}2/FILE
74096c
+
74096c
+# check permission bits.
74096c
+EXPECT '755' stat -c %a $B0/${V0}0/FILE
74096c
+EXPECT '755' stat -c %a $B0/${V0}1/FILE
74096c
+EXPECT '755' stat -c %a $B0/${V0}2/FILE
74096c
+
74096c
+EXPECT_WITHIN $UMOUNT_TIMEOUT "Y" force_umount $M0
74096c
+cleanup;
74096c
diff --git a/xlators/cluster/afr/src/afr-self-heal-metadata.c b/xlators/cluster/afr/src/afr-self-heal-metadata.c
74096c
index f4e31b6..03f43ba 100644
74096c
--- a/xlators/cluster/afr/src/afr-self-heal-metadata.c
74096c
+++ b/xlators/cluster/afr/src/afr-self-heal-metadata.c
74096c
@@ -190,6 +190,59 @@ out:
74096c
     return ret;
74096c
 }
74096c
 
74096c
+static int
74096c
+__afr_selfheal_metadata_mark_pending_xattrs(call_frame_t *frame, xlator_t *this,
74096c
+                                            inode_t *inode,
74096c
+                                            struct afr_reply *replies,
74096c
+                                            unsigned char *sources)
74096c
+{
74096c
+    int ret = 0;
74096c
+    int i = 0;
74096c
+    int m_idx = 0;
74096c
+    afr_private_t *priv = NULL;
74096c
+    int raw[AFR_NUM_CHANGE_LOGS] = {0};
74096c
+    dict_t *xattr = NULL;
74096c
+
74096c
+    priv = this->private;
74096c
+    m_idx = afr_index_for_transaction_type(AFR_METADATA_TRANSACTION);
74096c
+    raw[m_idx] = 1;
74096c
+
74096c
+    xattr = dict_new();
74096c
+    if (!xattr)
74096c
+        return -ENOMEM;
74096c
+
74096c
+    for (i = 0; i < priv->child_count; i++) {
74096c
+        if (sources[i])
74096c
+            continue;
74096c
+        ret = dict_set_static_bin(xattr, priv->pending_key[i], raw,
74096c
+                                  sizeof(int) * AFR_NUM_CHANGE_LOGS);
74096c
+        if (ret) {
74096c
+            ret = -1;
74096c
+            goto out;
74096c
+        }
74096c
+    }
74096c
+
74096c
+    for (i = 0; i < priv->child_count; i++) {
74096c
+        if (!sources[i])
74096c
+            continue;
74096c
+        ret = afr_selfheal_post_op(frame, this, inode, i, xattr, NULL);
74096c
+        if (ret < 0) {
74096c
+            gf_msg(this->name, GF_LOG_INFO, -ret, AFR_MSG_SELF_HEAL_INFO,
74096c
+                   "Failed to set pending metadata xattr on child %d for %s", i,
74096c
+                   uuid_utoa(inode->gfid));
74096c
+            goto out;
74096c
+        }
74096c
+    }
74096c
+
74096c
+    afr_replies_wipe(replies, priv->child_count);
74096c
+    ret = afr_selfheal_unlocked_discover(frame, inode, inode->gfid, replies);
74096c
+
74096c
+out:
74096c
+    if (xattr)
74096c
+        dict_unref(xattr);
74096c
+    return ret;
74096c
+}
74096c
+
74096c
 /*
74096c
  * Look for mismatching uid/gid or mode or user xattrs even if
74096c
  * AFR xattrs don't say so, and pick one arbitrarily as winner. */
74096c
@@ -210,6 +263,7 @@ __afr_selfheal_metadata_finalize_source(call_frame_t *frame, xlator_t *this,
74096c
     };
74096c
     int source = -1;
74096c
     int sources_count = 0;
74096c
+    int ret = 0;
74096c
 
74096c
     priv = this->private;
74096c
 
74096c
@@ -300,7 +354,13 @@ __afr_selfheal_metadata_finalize_source(call_frame_t *frame, xlator_t *this,
74096c
             healed_sinks[i] = 1;
74096c
         }
74096c
     }
74096c
-
74096c
+    if ((sources_count == priv->child_count) && (source > -1) &&
74096c
+        (AFR_COUNT(healed_sinks, priv->child_count) != 0)) {
74096c
+        ret = __afr_selfheal_metadata_mark_pending_xattrs(frame, this, inode,
74096c
+                                                          replies, sources);
74096c
+        if (ret < 0)
74096c
+            return ret;
74096c
+    }
74096c
 out:
74096c
     afr_mark_active_sinks(this, sources, locked_on, healed_sinks);
74096c
     return source;
74096c
-- 
74096c
1.8.3.1
74096c