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