diff options
author | Krutika Dhananjay <kdhananj@redhat.com> | 2014-08-21 17:27:17 +0530 |
---|---|---|
committer | Pranith Kumar Karampuri <pkarampu@redhat.com> | 2014-09-02 07:57:22 -0700 |
commit | 6c4325ca57bca72d10e5172f8423262cdb3a379c (patch) | |
tree | b1337a1865d4b5500fda362fb4bf8324c0f9d3c7 | |
parent | 2c0a694b8d910c530899077c1d242ad1ea250965 (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.t | 129 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-common.c | 20 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-common.c | 9 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-data.c | 3 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-entry.c | 31 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-metadata.c | 4 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-name.c | 366 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal.h | 20 |
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 */ |