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