summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrutika Dhananjay <kdhananj@redhat.com>2014-08-21 17:27:17 +0530
committerPranith Kumar Karampuri <pkarampu@redhat.com>2014-09-02 07:57:22 -0700
commit6c4325ca57bca72d10e5172f8423262cdb3a379c (patch)
treeb1337a1865d4b5500fda362fb4bf8324c0f9d3c7
parent2c0a694b8d910c530899077c1d242ad1ea250965 (diff)
cluster/afr: Propagate EIO on inode's type mismatch
Original author of the test script: Pranith Kumar K <pkarampu@redhat.com> Change-Id: If515ecefd3c17f85f175b6a8cb4b78ce8c916de2 BUG: 1132469 Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com> Reviewed-on: http://review.gluster.org/8574 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/basic/afr/gfid-self-heal.t129
-rw-r--r--xlators/cluster/afr/src/afr-common.c20
-rw-r--r--xlators/cluster/afr/src/afr-self-heal-common.c9
-rw-r--r--xlators/cluster/afr/src/afr-self-heal-data.c3
-rw-r--r--xlators/cluster/afr/src/afr-self-heal-entry.c31
-rw-r--r--xlators/cluster/afr/src/afr-self-heal-metadata.c4
-rw-r--r--xlators/cluster/afr/src/afr-self-heal-name.c366
-rw-r--r--xlators/cluster/afr/src/afr-self-heal.h20
8 files changed, 462 insertions, 120 deletions
diff --git a/tests/basic/afr/gfid-self-heal.t b/tests/basic/afr/gfid-self-heal.t
new file mode 100644
index 00000000000..f9d88c5d21a
--- /dev/null
+++ b/tests/basic/afr/gfid-self-heal.t
@@ -0,0 +1,129 @@
+#!/bin/bash
+
+#Tests for files without gfids
+
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+
+cleanup;
+
+TEST glusterd
+TEST pidof glusterd
+TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1}
+TEST $CLI volume set $V0 self-heal-daemon off
+TEST $CLI volume set $V0 nfs.disable on
+TEST touch $B0/${V0}{0,1}/{1,2,3,4}
+TEST $CLI volume start $V0
+
+TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0
+#Test that readdir returns entries even when no gfids are present
+EXPECT 4 echo $(ls -l $M0 | grep -vi total | wc -l)
+sleep 2;
+#stat the files and check that the files have same gfids on the bricks now
+TEST stat $M0/1
+gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/1)
+gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/1)
+TEST "[[ ! -z $gfid_0 ]]"
+EXPECT $gfid_0 echo $gfid_1
+
+TEST stat $M0/2
+gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/2)
+gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/2)
+TEST "[[ ! -z $gfid_0 ]]"
+EXPECT $gfid_0 echo $gfid_1
+
+TEST stat $M0/3
+gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/3)
+gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/3)
+TEST "[[ ! -z $gfid_0 ]]"
+EXPECT $gfid_0 echo $gfid_1
+
+TEST stat $M0/4
+gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/4)
+gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/4)
+TEST "[[ ! -z $gfid_0 ]]"
+EXPECT $gfid_0 echo $gfid_1
+
+#Check gfid self-heal happens from one brick to other when a file has missing
+#gfid
+TEST kill_brick $V0 $H0 $B0/${V0}0
+TEST touch $M0/a
+gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/a)
+TEST touch $B0/${V0}0/a
+$CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
+TEST stat $M0/a
+gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/a)
+EXPECT $gfid_1 echo $gfid_0
+
+#Check gfid self-heal doesn't happen from one brick to other when type mismatch
+#is present for a name, without any xattrs
+TEST kill_brick $V0 $H0 $B0/${V0}0
+TEST touch $M0/b
+TEST mkdir $B0/${V0}0/b
+TEST setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1
+$CLI volume start $V0 force
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
+TEST ! stat $M0/b
+gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/b)
+TEST "[[ -z \"$gfid_0\" ]]"
+
+#Check gfid assigning doesn't happen when there is type mismatch
+TEST touch $B0/${V0}1/c
+TEST mkdir $B0/${V0}0/c
+TEST ! stat $M0/c
+gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/c)
+gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/c)
+TEST "[[ -z \"$gfid_1\" ]]"
+TEST "[[ -z \"$gfid_0\" ]]"
+
+#Check gfid assigning doesn't happen only when even one brick is down to prevent
+# gfid split-brain
+TEST kill_brick $V0 $H0 $B0/${V0}0
+TEST touch $B0/${V0}1/d
+TEST ! stat $M0/d
+gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/d)
+TEST "[[ -z \"$gfid_1\" ]]"
+TEST $CLI volume start $V0 force;
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
+EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
+
+#Check gfid self-heal doesn't happen from one brick to other when type mismatch
+#is present for a name without any pending xattrs
+#TEST kill_brick $V0 $H0 $B0/${V0}0
+#TEST touch $M0/e
+#TEST $CLI volume start $V0 force;
+#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
+#TEST kill_brick $V0 $H0 $B0/${V0}1
+#TEST mkdir $M0/e
+#TEST $CLI volume stop $V0 force;
+#TEST setfattr -x trusted.gfid $B0/${V0}1/e
+#TEST setfattr -x trusted.gfid $B0/${V0}0/e
+#TEST $CLI volume set $V0 cluster.entry-self-heal off
+#$CLI volume start $V0 force
+#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
+#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
+#TEST ! stat $M0/e
+#gfid_1=$(gf_get_gfid_xattr $B0/${V0}1/e)
+#gfid_0=$(gf_get_gfid_xattr $B0/${V0}0/e)
+#TEST "[[ -z \"$gfid_1\" ]]"
+#TEST "[[ -z \"$gfid_0\" ]]"
+
+#Check if lookup fails with gfid-mismatch of a file
+#is present for a name without any pending xattrs
+#TEST kill_brick $V0 $H0 $B0/${V0}0
+#TEST touch $M0/f
+#$CLI volume start $V0 force
+#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
+#TEST kill_brick $V0 $H0 $B0/${V0}1
+#TEST touch $M0/f
+#simulate no pending changelog
+#$CLI volume stop $V0 force
+#TEST setfattr -x trusted.afr.$V0-client-0 $B0/${V0}1
+#TEST setfattr -x trusted.afr.$V0-client-1 $B0/${V0}0
+#$CLI volume start $V0 force
+#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 0
+#EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status $V0 1
+#TEST ! stat $M0/f
+
+cleanup
diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c
index 8ab67af405f..2a6b0c957fb 100644
--- a/xlators/cluster/afr/src/afr-common.c
+++ b/xlators/cluster/afr/src/afr-common.c
@@ -1219,9 +1219,8 @@ afr_lookup_done (call_frame_t *frame, xlator_t *this)
continue;
}
- if (!uuid_compare (replies[i].poststat.ia_gfid,
- read_gfid))
- continue;
+ if (!uuid_compare (replies[i].poststat.ia_gfid, read_gfid))
+ continue;
can_interpret = _gf_false;
@@ -1442,6 +1441,7 @@ afr_attempt_local_discovery (xlator_t *this, int32_t child_index)
int
afr_lookup_selfheal_wrap (void *opaque)
{
+ int ret = 0;
call_frame_t *frame = opaque;
afr_local_t *local = NULL;
xlator_t *this = NULL;
@@ -1450,19 +1450,25 @@ afr_lookup_selfheal_wrap (void *opaque)
local = frame->local;
this = frame->this;
- afr_selfheal_name (frame->this, local->loc.pargfid, local->loc.name,
- &local->cont.lookup.gfid_req);
+ ret = afr_selfheal_name (frame->this, local->loc.pargfid,
+ local->loc.name, &local->cont.lookup.gfid_req);
+ if (ret == -EIO)
+ goto unwind;
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);
+ local->child_up, NULL);
if (inode)
inode_unref (inode);
+
afr_lookup_done (frame, this);
+ return 0;
- return 0;
+unwind:
+ AFR_STACK_UNWIND (lookup, frame, -1, EIO, NULL, NULL, NULL, NULL);
+ return 0;
}
diff --git a/xlators/cluster/afr/src/afr-self-heal-common.c b/xlators/cluster/afr/src/afr-self-heal-common.c
index 1c3d4a5dc86..9a88a7d9e5c 100644
--- a/xlators/cluster/afr/src/afr-self-heal-common.c
+++ b/xlators/cluster/afr/src/afr-self-heal-common.c
@@ -312,8 +312,7 @@ afr_selfheal_extract_xattr (xlator_t *this, struct afr_reply *replies,
*/
int
-afr_selfheal_find_direction (call_frame_t *frame, xlator_t *this,
- struct afr_reply *replies,
+afr_selfheal_find_direction (xlator_t *this, struct afr_reply *replies,
afr_transaction_type type, unsigned char *locked_on,
unsigned char *sources, unsigned char *sinks)
{
@@ -415,7 +414,7 @@ afr_selfheal_discover_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
inode_t *
afr_selfheal_unlocked_lookup_on (call_frame_t *frame, inode_t *parent,
const char *name, struct afr_reply *replies,
- unsigned char *lookup_on)
+ unsigned char *lookup_on, dict_t *xattr)
{
loc_t loc = {0, };
dict_t *xattr_req = NULL;
@@ -430,6 +429,9 @@ afr_selfheal_unlocked_lookup_on (call_frame_t *frame, inode_t *parent,
if (!xattr_req)
return NULL;
+ if (xattr)
+ dict_copy (xattr, xattr_req);
+
if (afr_xattr_req_prepare (frame->this, xattr_req) != 0) {
dict_destroy (xattr_req);
return NULL;
@@ -457,7 +459,6 @@ afr_selfheal_unlocked_lookup_on (call_frame_t *frame, inode_t *parent,
return inode;
}
-
int
afr_selfheal_unlocked_discover_on (call_frame_t *frame, inode_t *inode,
uuid_t gfid, struct afr_reply *replies,
diff --git a/xlators/cluster/afr/src/afr-self-heal-data.c b/xlators/cluster/afr/src/afr-self-heal-data.c
index a8a2607dbe9..455648b7564 100644
--- a/xlators/cluster/afr/src/afr-self-heal-data.c
+++ b/xlators/cluster/afr/src/afr-self-heal-data.c
@@ -455,8 +455,7 @@ __afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd,
if (ret)
return ret;
- ret = afr_selfheal_find_direction (frame, this, replies,
- AFR_DATA_TRANSACTION,
+ ret = afr_selfheal_find_direction (this, replies, AFR_DATA_TRANSACTION,
locked_on, sources, sinks);
if (ret)
return ret;
diff --git a/xlators/cluster/afr/src/afr-self-heal-entry.c b/xlators/cluster/afr/src/afr-self-heal-entry.c
index 97397c1b098..cb682a7dccc 100644
--- a/xlators/cluster/afr/src/afr-self-heal-entry.c
+++ b/xlators/cluster/afr/src/afr-self-heal-entry.c
@@ -21,9 +21,8 @@
static int
-afr_selfheal_entry_delete (call_frame_t *frame, xlator_t *this, inode_t *dir,
- const char *name, inode_t *inode, int child,
- struct afr_reply *replies)
+afr_selfheal_entry_delete (xlator_t *this, inode_t *dir, const char *name,
+ inode_t *inode, int child, struct afr_reply *replies)
{
afr_private_t *priv = NULL;
xlator_t *subvol = NULL;
@@ -68,9 +67,9 @@ afr_selfheal_entry_delete (call_frame_t *frame, xlator_t *this, inode_t *dir,
int
-afr_selfheal_recreate_entry (call_frame_t *frame, xlator_t *this, int dst,
- int source, inode_t *dir, const char *name,
- inode_t *inode, struct afr_reply *replies)
+afr_selfheal_recreate_entry (xlator_t *this, int dst, int source, inode_t *dir,
+ const char *name, inode_t *inode,
+ struct afr_reply *replies)
{
int ret = 0;
loc_t loc = {0,};
@@ -93,8 +92,7 @@ afr_selfheal_recreate_entry (call_frame_t *frame, xlator_t *this, int dst,
loc.name = name;
loc.inode = inode_ref (inode);
- ret = afr_selfheal_entry_delete (frame, this, dir, name, inode, dst,
- replies);
+ ret = afr_selfheal_entry_delete (this, dir, name, inode, dst, replies);
if (ret)
goto out;
@@ -214,14 +212,14 @@ __afr_selfheal_heal_dirent (call_frame_t *frame, xlator_t *this, fd_t *fd,
continue;
if (replies[source].op_ret == -1 &&
replies[source].op_errno == ENOENT) {
- ret = afr_selfheal_entry_delete (frame, this, fd->inode,
- name, inode, i, replies);
+ ret = afr_selfheal_entry_delete (this, fd->inode, name,
+ inode, i, replies);
} else {
if (!uuid_compare (replies[i].poststat.ia_gfid,
replies[source].poststat.ia_gfid))
continue;
- ret = afr_selfheal_recreate_entry (frame, this, i, source,
+ ret = afr_selfheal_recreate_entry (this, i, source,
fd->inode, name, inode,
replies);
if (ret > 0) {
@@ -272,9 +270,8 @@ __afr_selfheal_merge_dirent (call_frame_t *frame, xlator_t *this, fd_t *fd,
if (replies[i].op_errno != ENOENT)
continue;
- ret = afr_selfheal_recreate_entry (frame, this, i, source,
- fd->inode, name, inode,
- replies);
+ ret = afr_selfheal_recreate_entry (this, i, source, fd->inode,
+ name, inode, replies);
}
return ret;
@@ -327,7 +324,8 @@ afr_selfheal_entry_dirent (call_frame_t *frame, xlator_t *this, fd_t *fd,
}
inode = afr_selfheal_unlocked_lookup_on (frame, fd->inode, name,
- replies, locked_on);
+ replies, locked_on,
+ NULL);
if (!inode) {
ret = -ENOMEM;
goto unlock;
@@ -476,8 +474,7 @@ __afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd,
if (ret)
return ret;
- ret = afr_selfheal_find_direction (frame, this, replies,
- AFR_ENTRY_TRANSACTION,
+ ret = afr_selfheal_find_direction (this, replies, AFR_ENTRY_TRANSACTION,
locked_on, sources, sinks);
if (ret)
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 efbfd63aa21..dc7825d3d16 100644
--- a/xlators/cluster/afr/src/afr-self-heal-metadata.c
+++ b/xlators/cluster/afr/src/afr-self-heal-metadata.c
@@ -160,8 +160,8 @@ __afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, inode_t *i
if (ret)
return ret;
- ret = afr_selfheal_find_direction (frame, this, replies,
- AFR_METADATA_TRANSACTION,
+ ret = afr_selfheal_find_direction (this, replies,
+ AFR_METADATA_TRANSACTION,
locked_on, sources, sinks);
if (ret)
return ret;
diff --git a/xlators/cluster/afr/src/afr-self-heal-name.c b/xlators/cluster/afr/src/afr-self-heal-name.c
index f1626cc034e..9e7bb3bffa4 100644
--- a/xlators/cluster/afr/src/afr-self-heal-name.c
+++ b/xlators/cluster/afr/src/afr-self-heal-name.c
@@ -19,29 +19,43 @@
int
-__afr_selfheal_assign_gfid (call_frame_t *frame, xlator_t *this, inode_t *parent,
- uuid_t pargfid, const char *bname, inode_t *inode,
- struct afr_reply *replies, void *gfid)
+__afr_selfheal_assign_gfid (xlator_t *this, inode_t *parent, uuid_t pargfid,
+ const char *bname, inode_t *inode,
+ struct afr_reply *replies, void *gfid,
+ unsigned char *locked_on,
+ gf_boolean_t is_gfid_absent)
{
- int i = 0;
- afr_private_t *priv = NULL;
- dict_t *xdata = NULL;
- int ret = 0;
- loc_t loc = {0, };
+ int ret = 0;
+ int up_count = 0;
+ int locked_count = 0;
+ afr_private_t *priv = NULL;
+ dict_t *xdata = NULL;
+ loc_t loc = {0, };
+ call_frame_t *new_frame = NULL;
+ afr_local_t *new_local = NULL;
priv = this->private;
+ new_frame = afr_frame_create (this);
+ if (!new_frame) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ new_local = new_frame->local;
+
uuid_copy (parent->gfid, pargfid);
xdata = dict_new ();
if (!xdata) {
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
ret = dict_set_static_bin (xdata, "gfid-req", gfid, 16);
if (ret) {
- dict_destroy (xdata);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out;
}
loc.parent = inode_ref (parent);
@@ -49,24 +63,53 @@ __afr_selfheal_assign_gfid (call_frame_t *frame, xlator_t *this, inode_t *parent
uuid_copy (loc.pargfid, pargfid);
loc.name = bname;
- for (i = 0; i < priv->child_count; i++) {
- if (replies[i].op_ret == 0 || replies[i].op_errno != ENODATA)
- continue;
+ if (is_gfid_absent) {
+ /* Ensure all children of AFR are up before performing gfid heal, to
+ * guard against the possibility of gfid split brain. */
+
+ up_count = AFR_COUNT (priv->child_up, priv->child_count);
+ if (up_count != priv->child_count) {
+ ret = -EIO;
+ goto out;
+ }
+
+ locked_count = AFR_COUNT (locked_on, priv->child_count);
+ if (locked_count != priv->child_count) {
+ ret = -EIO;
+ goto out;
+ }
+ }
- ret = syncop_lookup (priv->children[i], &loc, xdata, 0, 0, 0);
- }
+ /* Clear out old replies here and wind lookup on all locked
+ * subvolumes to achieve two things:
+ * a. gfid heal on those subvolumes that do not have gfid associated
+ * with the inode, and
+ * b. refresh replies, which can be consumed by
+ * __afr_selfheal_name_impunge().
+ */
+
+ afr_replies_wipe (replies, priv->child_count);
+
+ AFR_ONLIST (locked_on, new_frame, afr_selfheal_discover_cbk, lookup,
+ &loc, xdata);
+ afr_replies_copy (replies, new_local->replies, priv->child_count);
+
+out:
loc_wipe (&loc);
- dict_unref (xdata);
+ if (xdata)
+ dict_unref (xdata);
+ if (new_frame)
+ AFR_STACK_DESTROY (new_frame);
return ret;
}
int
-__afr_selfheal_name_impunge (call_frame_t *frame, xlator_t *this, inode_t *parent,
- uuid_t pargfid, const char *bname, inode_t *inode,
- struct afr_reply *replies, int gfid_idx)
+__afr_selfheal_name_impunge (xlator_t *this, inode_t *parent, uuid_t pargfid,
+ const char *bname, inode_t *inode,
+ struct afr_reply *replies, int gfid_idx)
{
int i = 0;
afr_private_t *priv = NULL;
@@ -84,8 +127,8 @@ __afr_selfheal_name_impunge (call_frame_t *frame, xlator_t *this, inode_t *paren
replies[gfid_idx].poststat.ia_gfid) == 0)
continue;
- ret |= afr_selfheal_recreate_entry (frame, this, i, gfid_idx,
- parent, bname, inode, replies);
+ ret |= afr_selfheal_recreate_entry (this, i, gfid_idx, parent,
+ bname, inode, replies);
}
return ret;
@@ -93,8 +136,8 @@ __afr_selfheal_name_impunge (call_frame_t *frame, xlator_t *this, inode_t *paren
int
-__afr_selfheal_name_expunge (call_frame_t *frame, xlator_t *this, inode_t *parent,
- uuid_t pargfid, const char *bname, inode_t *inode,
+__afr_selfheal_name_expunge (xlator_t *this, inode_t *parent, uuid_t pargfid,
+ const char *bname, inode_t *inode,
struct afr_reply *replies)
{
loc_t loc = {0, };
@@ -143,25 +186,44 @@ __afr_selfheal_name_expunge (call_frame_t *frame, xlator_t *this, inode_t *paren
}
+/* This function is to be called after ensuring that there is no gfid mismatch
+ * for the inode across multiple sources
+ */
+static int
+afr_selfheal_gfid_idx_get (xlator_t *this, struct afr_reply *replies,
+ unsigned char *sources)
+{
+ int i = 0;
+ int gfid_idx = -1;
+ afr_private_t *priv = NULL;
+
+ priv = this->private;
-int
-__afr_selfheal_name_do (call_frame_t *frame, xlator_t *this, inode_t *parent,
- uuid_t pargfid, const char *bname, inode_t *inode,
- unsigned char *sources, unsigned char *sinks,
- unsigned char *healed_sinks, int source,
- unsigned char *locked_on, struct afr_reply *replies,
- void *gfid_req)
+ for (i = 0; i < priv->child_count; i++) {
+ if (!replies[i].valid)
+ continue;
+
+ if (!sources[i])
+ continue;
+
+ if (uuid_is_null (replies[i].poststat.ia_gfid))
+ continue;
+
+ gfid_idx = i;
+ break;
+ }
+ return gfid_idx;
+}
+
+static gf_boolean_t
+afr_selfheal_name_need_heal_check (xlator_t *this, struct afr_reply *replies)
{
- int i = 0;
- afr_private_t *priv = NULL;
- void* gfid = NULL;
- int gfid_idx = -1;
- gf_boolean_t source_is_empty = _gf_true;
- gf_boolean_t need_heal = _gf_false;
- int first_idx = -1;
- char g1[64],g2[64];
+ int i = 0;
+ int first_idx = -1;
+ gf_boolean_t need_heal = _gf_false;
+ afr_private_t *priv = NULL;
- priv = this->private;
+ priv = this->private;
for (i = 0; i < priv->child_count; i++) {
if (!replies[i].valid)
@@ -182,29 +244,76 @@ __afr_selfheal_name_do (call_frame_t *frame, xlator_t *this, inode_t *parent,
if (uuid_compare (replies[i].poststat.ia_gfid,
replies[first_idx].poststat.ia_gfid))
need_heal = _gf_true;
+
+ if ((replies[i].op_ret == 0) &&
+ (uuid_is_null(replies[i].poststat.ia_gfid)))
+ need_heal = _gf_true;
+
}
- if (!need_heal)
- return 0;
+ return need_heal;
+}
- for (i = 0; i < priv->child_count; i++) {
- if (!sources[i])
+static int
+afr_selfheal_name_type_mismatch_check (xlator_t *this, struct afr_reply *replies,
+ int source, unsigned char *sources,
+ uuid_t pargfid, const char *bname)
+{
+ int i = 0;
+ int type_idx = -1;
+ ia_type_t inode_type = IA_INVAL;
+ afr_private_t *priv = NULL;
+
+ priv = this->private;
+
+ for (i = 0; i < priv->child_count; i++) {
+ if (!replies[i].valid)
continue;
- if (replies[i].op_ret == -1 && replies[i].op_errno == ENOENT)
+ if (replies[i].poststat.ia_type == IA_INVAL)
continue;
- source_is_empty = _gf_false;
- break;
- }
+ if (inode_type == IA_INVAL) {
+ inode_type = replies[i].poststat.ia_type;
+ type_idx = i;
+ continue;
+ }
+
+ if (sources[i] || source == -1) {
+ if ((sources[type_idx] || source == -1) &&
+ (inode_type != replies[i].poststat.ia_type)) {
+ gf_msg (this->name, GF_LOG_WARNING, 0,
+ AFR_MSG_SPLIT_BRAIN,
+ "Type mismatch for <gfid:%s>/%s: "
+ "%d on %s and %d on %s",
+ uuid_utoa(pargfid), bname,
+ replies[i].poststat.ia_type,
+ priv->children[i]->name,
+ replies[type_idx].poststat.ia_type,
+ priv->children[type_idx]->name);
+ return -EIO;
+ }
+ }
+ inode_type = replies[i].poststat.ia_type;
+ type_idx = i;
+ continue;
+ }
+ return 0;
+}
- if (source == -1)
- source_is_empty = _gf_false;
+static int
+afr_selfheal_name_gfid_mismatch_check (xlator_t *this, struct afr_reply *replies,
+ int source, unsigned char *sources,
+ int *gfid_idx, uuid_t pargfid,
+ const char *bname)
+{
+ int i = 0;
+ int gfid_idx_iter = -1;
+ void *gfid = NULL;
+ afr_private_t *priv = NULL;
+ char g1[64], g2[64];
- if (source_is_empty) {
- return __afr_selfheal_name_expunge (frame, this, parent, pargfid,
- bname, inode, replies);
- }
+ priv = this->private;
for (i = 0; i < priv->child_count; i++) {
if (!replies[i].valid)
@@ -215,13 +324,12 @@ __afr_selfheal_name_do (call_frame_t *frame, xlator_t *this, inode_t *parent,
if (!gfid) {
gfid = &replies[i].poststat.ia_gfid;
- gfid_idx = i;
+ gfid_idx_iter = i;
continue;
}
if (sources[i] || source == -1) {
- if (gfid_idx != -1 &&
- (sources[gfid_idx] || source == -1) &&
+ if ((sources[gfid_idx_iter] || source == -1) &&
uuid_compare (gfid, replies[i].poststat.ia_gfid)) {
gf_msg (this->name, GF_LOG_WARNING, 0,
AFR_MSG_SPLIT_BRAIN,
@@ -230,34 +338,110 @@ __afr_selfheal_name_do (call_frame_t *frame, xlator_t *this, inode_t *parent,
uuid_utoa (pargfid), bname,
uuid_utoa_r (replies[i].poststat.ia_gfid, g1),
priv->children[i]->name,
- uuid_utoa_r (replies[gfid_idx].poststat.ia_gfid, g2),
- priv->children[gfid_idx]->name);
- return -1;
+ uuid_utoa_r (replies[gfid_idx_iter].poststat.ia_gfid, g2),
+ priv->children[gfid_idx_iter]->name);
+ return -EIO;
}
gfid = &replies[i].poststat.ia_gfid;
- gfid_idx = i;
+ gfid_idx_iter = i;
continue;
}
}
+ *gfid_idx = gfid_idx_iter;
+ return 0;
+}
+
+static gf_boolean_t
+afr_selfheal_name_source_empty_check (xlator_t *this, struct afr_reply *replies,
+ unsigned char *sources, int source)
+{
+ int i = 0;
+ afr_private_t *priv = NULL;
+ gf_boolean_t source_is_empty = _gf_true;
+
+ priv = this->private;
+
+ if (source == -1) {
+ source_is_empty = _gf_false;
+ goto out;
+ }
+
+ for (i = 0; i < priv->child_count; i++) {
+ if (!sources[i])
+ continue;
+
+ if (replies[i].op_ret == -1 && replies[i].op_errno == ENOENT)
+ continue;
+
+ source_is_empty = _gf_false;
+ break;
+ }
+out:
+ return source_is_empty;
+}
+
+int
+__afr_selfheal_name_do (xlator_t *this, inode_t *parent, uuid_t pargfid,
+ const char *bname, inode_t *inode,
+ unsigned char *sources, unsigned char *sinks,
+ unsigned char *healed_sinks, int source,
+ unsigned char *locked_on, struct afr_reply *replies,
+ void *gfid_req)
+{
+ int gfid_idx = -1;
+ int ret = -1;
+ void *gfid = NULL;
+ gf_boolean_t source_is_empty = _gf_true;
+ gf_boolean_t need_heal = _gf_false;
+ gf_boolean_t is_gfid_absent = _gf_false;
+
+ need_heal = afr_selfheal_name_need_heal_check (this, replies);
+ if (!need_heal)
+ return 0;
+
+ source_is_empty = afr_selfheal_name_source_empty_check (this, replies,
+ sources,
+ source);
+ if (source_is_empty)
+ return __afr_selfheal_name_expunge (this, parent, pargfid,
+ bname, inode, replies);
+
+ ret = afr_selfheal_name_type_mismatch_check (this, replies, source,
+ sources, pargfid, bname);
+ if (ret)
+ return ret;
+
+ ret = afr_selfheal_name_gfid_mismatch_check (this, replies, source,
+ sources, &gfid_idx,
+ pargfid, bname);
+ if (ret)
+ return ret;
+
if (gfid_idx == -1) {
if (!gfid_req || uuid_is_null (gfid_req))
return -1;
gfid = gfid_req;
+ } else {
+ gfid = &replies[gfid_idx].poststat.ia_gfid;
}
- __afr_selfheal_assign_gfid (frame, this, parent, pargfid, bname, inode,
- replies, gfid);
- /*TODO:
- * once the gfid is assigned refresh the replies and carry on with
- * impunge. i.e. gfid_idx won't be -1.
- */
- if (gfid_idx == -1)
- return -1;
+ is_gfid_absent = (gfid_idx == -1) ? _gf_true : _gf_false;
+ ret = __afr_selfheal_assign_gfid (this, parent, pargfid, bname, inode,
+ replies, gfid, locked_on,
+ is_gfid_absent);
+ if (ret)
+ return ret;
+
+ if (gfid_idx == -1) {
+ gfid_idx = afr_selfheal_gfid_idx_get (this, replies, sources);
+ if (gfid_idx == -1)
+ return -1;
+ }
- return __afr_selfheal_name_impunge (frame, this, parent, pargfid,
- bname, inode, replies, gfid_idx);
+ return __afr_selfheal_name_impunge (this, parent, pargfid, bname, inode,
+ replies, gfid_idx);
}
@@ -310,8 +494,7 @@ __afr_selfheal_name_prepare (call_frame_t *frame, xlator_t *this, inode_t *paren
if (ret)
goto out;
- ret = afr_selfheal_find_direction (frame, this, replies,
- AFR_ENTRY_TRANSACTION,
+ ret = afr_selfheal_find_direction (this, replies, AFR_ENTRY_TRANSACTION,
locked_on, sources, sinks);
if (ret)
goto out;
@@ -355,6 +538,17 @@ afr_selfheal_name_do (call_frame_t *frame, xlator_t *this, inode_t *parent,
struct afr_reply *replies = NULL;
int ret = -1;
inode_t *inode = NULL;
+ dict_t *xattr = NULL;
+
+ xattr = dict_new ();
+ if (!xattr)
+ return -ENOMEM;
+
+ ret = dict_set_int32 (xattr, GF_GFIDLESS_LOOKUP, 1);
+ if (ret) {
+ dict_destroy (xattr);
+ return -1;
+ }
priv = this->private;
@@ -379,16 +573,17 @@ afr_selfheal_name_do (call_frame_t *frame, xlator_t *this, inode_t *parent,
if (ret)
goto unlock;
- inode = afr_selfheal_unlocked_lookup_on (frame, parent, bname,
- replies, locked_on);
+ inode = afr_selfheal_unlocked_lookup_on (frame, parent, bname,
+ replies, locked_on,
+ xattr);
if (!inode) {
ret = -ENOMEM;
goto unlock;
}
- ret = __afr_selfheal_name_do (frame, this, parent, pargfid, bname,
- inode, sources, sinks, healed_sinks,
- source, locked_on, replies,
+ ret = __afr_selfheal_name_do (this, parent, pargfid, bname,
+ inode, sources, sinks, healed_sinks,
+ source, locked_on, replies,
gfid_req);
}
unlock:
@@ -399,6 +594,8 @@ unlock:
if (replies)
afr_replies_wipe (replies, priv->child_count);
+ if (xattr)
+ dict_unref (xattr);
return ret;
}
@@ -420,7 +617,7 @@ afr_selfheal_name_unlocked_inspect (call_frame_t *frame, xlator_t *this,
replies = alloca0 (sizeof (*replies) * priv->child_count);
inode = afr_selfheal_unlocked_lookup_on (frame, parent, bname,
- replies, priv->child_up);
+ replies, priv->child_up, NULL);
if (!inode)
return -ENOMEM;
@@ -474,9 +671,14 @@ afr_selfheal_name (xlator_t *this, uuid_t pargfid, const char *bname,
if (ret)
goto out;
- if (need_heal)
- afr_selfheal_name_do (frame, this, parent, pargfid, bname,
- gfid_req);
+ if (need_heal) {
+ ret = afr_selfheal_name_do (frame, this, parent, pargfid, bname,
+ gfid_req);
+ if (ret)
+ goto out;
+ }
+
+ ret = 0;
out:
if (parent)
inode_unref (parent);
diff --git a/xlators/cluster/afr/src/afr-self-heal.h b/xlators/cluster/afr/src/afr-self-heal.h
index da0025bb600..84da0d8000f 100644
--- a/xlators/cluster/afr/src/afr-self-heal.h
+++ b/xlators/cluster/afr/src/afr-self-heal.h
@@ -132,11 +132,10 @@ afr_selfheal_unlocked_discover (call_frame_t *frame, inode_t *inode,
inode_t *
afr_selfheal_unlocked_lookup_on (call_frame_t *frame, inode_t *parent,
const char *name, struct afr_reply *replies,
- unsigned char *lookup_on);
+ unsigned char *lookup_on, dict_t *xattr);
int
-afr_selfheal_find_direction (call_frame_t *frame, xlator_t *this,
- struct afr_reply *replies,
+afr_selfheal_find_direction (xlator_t *this, struct afr_reply *replies,
afr_transaction_type type, unsigned char *locked_on,
unsigned char *sources, unsigned char *sinks);
@@ -151,9 +150,9 @@ afr_selfheal_undo_pending (call_frame_t *frame, xlator_t *this, inode_t *inode,
struct afr_reply *replies, unsigned char *locked_on);
int
-afr_selfheal_recreate_entry (call_frame_t *frame, xlator_t *this, int dst,
- int source, inode_t *dir, const char *name,
- inode_t *inode, struct afr_reply *replies);
+afr_selfheal_recreate_entry (xlator_t *this, int dst, int source, inode_t *dir,
+ const char *name, inode_t *inode,
+ struct afr_reply *replies);
int
afr_selfheal_post_op (call_frame_t *frame, xlator_t *this, inode_t *inode,
@@ -165,4 +164,13 @@ afr_frame_create (xlator_t *this);
inode_t *
afr_inode_find (xlator_t *this, uuid_t gfid);
+int
+afr_selfheal_discover_cbk (call_frame_t *frame, void *cookie, xlator_t *this,
+ int op_ret, int op_errno, inode_t *inode,
+ struct iatt *buf, dict_t *xdata,
+ struct iatt *parbuf);
+
+void
+afr_replies_copy (struct afr_reply *dst, struct afr_reply *src, int count);
+
#endif /* !_AFR_SELFHEAL_H */