summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRavishankar N <ravishankar@redhat.com>2014-09-03 20:49:53 +0000
committerPranith Kumar Karampuri <pkarampu@redhat.com>2014-09-05 22:19:33 -0700
commit15a2088da508539a292f2a1863377dc40d264c8c (patch)
treeed4d10aa233ff14f901a5071cbad994fd20303c5
parentd2600dfda2b8f87b5f08d96abfb2abc0677151e0 (diff)
cluster/afr: perform list-xattr during lookup
Detect and heal mismatching user extended attributes during lookup. 'Forward' port of http://review.gluster.org/#/c/7444/ Change-Id: Id03c9746f083ffd3014711d0b3a2e5a71a45eed4 BUG: 1134691 Signed-off-by: Ravishankar N <ravishankar@redhat.com> Reviewed-on: http://review.gluster.org/8558 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Pranith Kumar Karampuri <pkarampu@redhat.com> Tested-by: Pranith Kumar Karampuri <pkarampu@redhat.com>
-rw-r--r--tests/bugs/bug-1130892.t2
-rw-r--r--tests/bugs/bug-1134691-afr-lookup-metadata-heal.t50
-rw-r--r--xlators/cluster/afr/src/afr-common.c198
-rw-r--r--xlators/cluster/afr/src/afr-self-heal-metadata.c30
-rw-r--r--xlators/cluster/afr/src/afr-self-heal.h2
-rw-r--r--xlators/cluster/afr/src/afr.h3
6 files changed, 273 insertions, 12 deletions
diff --git a/tests/bugs/bug-1130892.t b/tests/bugs/bug-1130892.t
index 438e795d571..206778f2938 100644
--- a/tests/bugs/bug-1130892.t
+++ b/tests/bugs/bug-1130892.t
@@ -49,7 +49,7 @@ TEST stat $M0/one
# Check pending xattrs
EXPECT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 data
EXPECT_NOT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 entry
-EXPECT_NOT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 metadata
+EXPECT "00000000" afr_get_specific_changelog_xattr $B0/${V0}-0/one trusted.afr.$V0-client-1 metadata
TEST gluster volume set $V0 self-heal-daemon on
EXPECT_WITHIN $PROCESS_UP_TIMEOUT "Y" glustershd_up_status
diff --git a/tests/bugs/bug-1134691-afr-lookup-metadata-heal.t b/tests/bugs/bug-1134691-afr-lookup-metadata-heal.t
new file mode 100644
index 00000000000..1fb1732a33f
--- /dev/null
+++ b/tests/bugs/bug-1134691-afr-lookup-metadata-heal.t
@@ -0,0 +1,50 @@
+#!/bin/bash
+#### Test iatt and user xattr heal from lookup code path ####
+
+. $(dirname $0)/../include.rc
+. $(dirname $0)/../volume.rc
+cleanup;
+
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume create $V0 replica 3 $H0:$B0/brick{0,1,2}
+TEST $CLI volume start $V0
+TEST $CLI volume set $V0 cluster.self-heal-daemon off
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0
+
+cd $M0
+TEST touch file
+TEST setfattr -n user.attribute1 -v "value" $B0/brick0/file
+TEST kill_brick $V0 $H0 $B0/brick2
+TEST chmod +x file
+iatt=$(stat -c "%g:%u:%A" file)
+
+TEST $CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 2
+
+#Trigger metadataheal
+TEST stat file
+
+#iattrs must be matching
+iatt1=$(stat -c "%g:%u:%A" $B0/brick0/file)
+iatt2=$(stat -c "%g:%u:%A" $B0/brick1/file)
+iatt3=$(stat -c "%g:%u:%A" $B0/brick2/file)
+EXPECT $iatt echo $iatt1
+EXPECT $iatt echo $iatt2
+EXPECT $iatt echo $iatt3
+
+#xattrs must be matching
+xatt1_cnt=$(getfattr -d $B0/brick0/file|wc|awk '{print $1}')
+xatt2_cnt=$(getfattr -d $B0/brick1/file|wc|awk '{print $1}')
+xatt3_cnt=$(getfattr -d $B0/brick2/file|wc|awk '{print $1}')
+EXPECT "$xatt1_cnt" echo $xatt2_cnt
+EXPECT "$xatt1_cnt" echo $xatt3_cnt
+
+#changelogs must be zero
+xattr1=$(get_hex_xattr trusted.afr.$V0-client-2 $B0/brick0/file)
+xattr2=$(get_hex_xattr trusted.afr.$V0-client-2 $B0/brick1/file)
+EXPECT "000000000000000000000000" echo $xattr1
+EXPECT "000000000000000000000000" echo $xattr2
+
+cd -
+cleanup;
diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c
index e9a05de2546..f290c1f8d1c 100644
--- a/xlators/cluster/afr/src/afr-common.c
+++ b/xlators/cluster/afr/src/afr-common.c
@@ -670,6 +670,12 @@ afr_xattr_req_prepare (xlator_t *this, dict_t *xattr_req)
"query flag");
}
+ ret = dict_set_int32 (xattr_req, "list-xattr", 1);
+ if (ret) {
+ gf_log (this->name, GF_LOG_DEBUG,
+ "Unable to set list-xattr in dict ");
+ }
+
return ret;
}
@@ -1140,6 +1146,73 @@ afr_handle_quota_size (call_frame_t *frame, xlator_t *this)
}
}
+static char *afr_ignore_xattrs[] = {
+ GLUSTERFS_OPEN_FD_COUNT,
+ GLUSTERFS_PARENT_ENTRYLK,
+ GLUSTERFS_ENTRYLK_COUNT,
+ GLUSTERFS_INODELK_COUNT,
+ GF_SELINUX_XATTR_KEY,
+ QUOTA_SIZE_KEY,
+ NULL
+};
+
+static gf_boolean_t
+afr_lookup_xattr_ignorable (char *key)
+{
+ int i = 0;
+
+ if (!strncmp (key, AFR_XATTR_PREFIX, strlen(AFR_XATTR_PREFIX)))
+ return _gf_true;
+ for (i = 0; afr_ignore_xattrs[i]; i++) {
+ if (!strcmp (key, afr_ignore_xattrs[i]))
+ return _gf_true;
+ }
+ return _gf_false;
+}
+
+int
+xattr_is_equal (dict_t *this, char *key1, data_t *value1, void *data)
+{
+ dict_t *xattr2 = (dict_t *)data;
+ data_t *value2 = NULL;
+
+ if (afr_lookup_xattr_ignorable (key1))
+ return 0;
+
+ value2 = dict_get (xattr2, key1);
+ if (!value2)
+ return -1;
+
+ if (value1->len != value2->len)
+ return -1;
+ if(memcmp(value1->data, value2->data, value1->len))
+ return -1;
+ else
+ return 0;
+
+}
+
+/* To conclude that both dicts are equal, we need to check if
+ * 1) For every key-val pair in dict1, a match is present in dict2
+ * 2) For every key-val pair in dict2, a match is present in dict1
+ * We need to do both because ignoring glusterfs' internal xattrs
+ * happens only in xattr_is_equal().
+ */
+static gf_boolean_t
+dicts_are_equal (dict_t *dict1, dict_t *dict2)
+{
+ int ret = 0;
+
+ ret = dict_foreach (dict1, xattr_is_equal, dict2);
+ if (ret == -1)
+ return _gf_false;
+
+ ret = dict_foreach (dict2, xattr_is_equal, dict1);
+ if (ret == -1)
+ return _gf_false;
+
+ return _gf_true;
+}
static void
afr_lookup_done (call_frame_t *frame, xlator_t *this)
@@ -1437,6 +1510,121 @@ afr_attempt_local_discovery (xlator_t *this, int32_t child_index)
&tmploc, GF_XATTR_PATHINFO_KEY, NULL);
}
+int
+afr_lookup_sh_metadata_wrap (void *opaque)
+{
+ call_frame_t *frame = opaque;
+ afr_local_t *local = NULL;
+ xlator_t *this = NULL;
+ inode_t *inode = NULL;
+ afr_private_t *priv = NULL;
+ struct afr_reply *replies = NULL;
+ int i= 0, first = -1;
+
+ local = frame->local;
+ this = frame->this;
+ priv = this->private;
+ replies = local->replies;
+
+ for (i =0; i < priv->child_count; i++) {
+ if(!replies[i].valid || replies[i].op_ret == -1)
+ continue;
+ first = i;
+ break;
+ }
+ if (first == -1)
+ goto out;
+
+ inode = afr_inode_link (local->inode,&replies[first].poststat);
+ if(!inode)
+ goto out;
+
+ afr_selfheal_metadata (frame, this, inode);
+ inode_forget (inode, 1);
+ inode_unref (inode);
+
+ afr_local_replies_wipe (local, this->private);
+ inode = afr_selfheal_unlocked_lookup_on (frame, local->loc.parent,
+ local->loc.name, local->replies,
+ local->child_up, NULL);
+ if (inode)
+ inode_unref (inode);
+out:
+ afr_lookup_done (frame, this);
+
+ return 0;
+}
+
+static gf_boolean_t
+afr_can_start_metadata_self_heal(call_frame_t *frame, xlator_t *this)
+{
+ afr_local_t *local = NULL;
+ afr_private_t *priv = NULL;
+ struct afr_reply *replies = NULL;
+ int i = 0, first = -1;
+ gf_boolean_t start = _gf_false;
+ struct iatt stbuf = {0, };
+
+ local = frame->local;
+ replies = local->replies;
+ priv = this->private;
+
+ for (i = 0; i < priv->child_count; i++) {
+ if(!replies[i].valid || replies[i].op_ret == -1)
+ continue;
+ if (first == -1) {
+ first = i;
+ stbuf = replies[i].poststat;
+ continue;
+ }
+
+ if (uuid_compare (stbuf.ia_gfid, replies[i].poststat.ia_gfid)) {
+ start = _gf_false;
+ break;
+ }
+ if (!IA_EQUAL (stbuf, replies[i].poststat, type)) {
+ start = _gf_false;
+ break;
+ }
+
+ /*Check if iattrs need heal*/
+ if ((!IA_EQUAL (stbuf, replies[i].poststat, uid)) ||
+ (!IA_EQUAL (stbuf, replies[i].poststat, gid)) ||
+ (!IA_EQUAL (stbuf, replies[i].poststat, prot))) {
+ start = _gf_true;
+ continue;
+ }
+
+ /*Check if xattrs need heal*/
+ if (!dicts_are_equal (replies[first].xdata, replies[i].xdata))
+ start = _gf_true;
+ }
+
+ return start;
+}
+
+int
+afr_lookup_metadata_heal_check (call_frame_t *frame, xlator_t *this)
+
+{
+ call_frame_t *heal = NULL;
+ int ret = 0;
+
+ if (!afr_can_start_metadata_self_heal (frame, this))
+ goto out;
+
+ heal = copy_frame (frame);
+ if (heal)
+ heal->root->pid = GF_CLIENT_PID_AFR_SELF_HEALD;
+ ret = synctask_new (this->ctx->env, afr_lookup_sh_metadata_wrap,
+ afr_refresh_selfheal_done, heal, frame);
+ if(ret)
+ goto out;
+ return ret;
+out:
+ afr_lookup_done (frame, this);
+ return ret;
+}
int
afr_lookup_selfheal_wrap (void *opaque)
@@ -1463,7 +1651,7 @@ afr_lookup_selfheal_wrap (void *opaque)
if (inode)
inode_unref (inode);
- afr_lookup_done (frame, this);
+ afr_lookup_metadata_heal_check(frame, this);
return 0;
unwind:
@@ -1519,11 +1707,11 @@ afr_lookup_entry_heal (call_frame_t *frame, xlator_t *this)
ret = synctask_new (this->ctx->env, afr_lookup_selfheal_wrap,
afr_refresh_selfheal_done, heal, frame);
if (ret)
- goto lookup_done;
- } else {
- lookup_done:
- afr_lookup_done (frame, this);
+ goto metadata_heal;
+ return ret;
}
+metadata_heal:
+ ret = afr_lookup_metadata_heal_check (frame, this);
return ret;
}
diff --git a/xlators/cluster/afr/src/afr-self-heal-metadata.c b/xlators/cluster/afr/src/afr-self-heal-metadata.c
index dc7825d3d16..e98728ba54f 100644
--- a/xlators/cluster/afr/src/afr-self-heal-metadata.c
+++ b/xlators/cluster/afr/src/afr-self-heal-metadata.c
@@ -82,12 +82,12 @@ __afr_selfheal_metadata_do (call_frame_t *frame, xlator_t *this, inode_t *inode,
/*
- * Look for mismatching uid/gid or mode even if xattrs don't say so, and
- * pick one arbitrarily as winner.
- */
+ * Look for mismatching uid/gid or mode or user xattrs even if
+ * AFR xattrs don't say so, and pick one arbitrarily as winner. */
static int
-__afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources,
+__afr_selfheal_metadata_finalize_source (call_frame_t *frame, xlator_t *this,
+ unsigned char *sources,
unsigned char *healed_sinks,
unsigned char *locked_on,
struct afr_reply *replies)
@@ -97,6 +97,7 @@ __afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources,
struct iatt first = {0, };
int source = -1;
int sources_count = 0;
+ int ret = 0;
priv = this->private;
@@ -124,11 +125,12 @@ __afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources,
if (source == -1) {
source = i;
first = replies[i].poststat;
+ break;
}
}
for (i = 0; i < priv->child_count; i++) {
- if (!sources[i])
+ if (!sources[i] || i == source)
continue;
if (!IA_EQUAL (first, replies[i].poststat, type) ||
!IA_EQUAL (first, replies[i].poststat, uid) ||
@@ -139,6 +141,22 @@ __afr_selfheal_metadata_finalize_source (xlator_t *this, unsigned char *sources,
}
}
+ for (i =0; i < priv->child_count; i++) {
+ if (!sources[i] || i == source)
+ continue;
+ if (replies[source].xdata->count != replies[i].xdata->count) {
+ sources[i] = 0;
+ healed_sinks[i] = 1;
+ continue;
+ }
+ ret = dict_foreach(replies[source].xdata, xattr_is_equal,
+ (void*)replies[i].xdata);
+ if (ret == -1) {
+ sources[i] = 0;
+ healed_sinks[i] = 1;
+ }
+ }
+
return source;
}
@@ -176,7 +194,7 @@ __afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, inode_t *i
*/
AFR_INTERSECT (healed_sinks, sinks, locked_on, priv->child_count);
- source = __afr_selfheal_metadata_finalize_source (this, sources,
+ source = __afr_selfheal_metadata_finalize_source (frame, this, sources,
healed_sinks,
locked_on, replies);
if (source < 0)
diff --git a/xlators/cluster/afr/src/afr-self-heal.h b/xlators/cluster/afr/src/afr-self-heal.h
index 2713ffa09bf..31f12a4e74a 100644
--- a/xlators/cluster/afr/src/afr-self-heal.h
+++ b/xlators/cluster/afr/src/afr-self-heal.h
@@ -179,4 +179,6 @@ afr_selfheal_newentry_mark (call_frame_t *frame, xlator_t *this, inode_t *inode,
int source, struct afr_reply *replies,
unsigned char *sources, unsigned char *newentry);
+inode_t*
+afr_inode_link (inode_t *inode, struct iatt *iatt);
#endif /* !_AFR_SELFHEAL_H */
diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h
index 4adbd5d5c83..c8224e16ab7 100644
--- a/xlators/cluster/afr/src/afr.h
+++ b/xlators/cluster/afr/src/afr.h
@@ -776,6 +776,9 @@ int32_t
afr_notify (xlator_t *this, int32_t event, void *data, void *data2);
int
+xattr_is_equal (dict_t *this, char *key1, data_t *value1, void *data);
+
+int
afr_init_entry_lockee (afr_entry_lockee_t *lockee, afr_local_t *local,
loc_t *loc, char *basename, int child_count);