diff options
-rw-r--r-- | heal/src/Makefile.am | 5 | ||||
-rw-r--r-- | heal/src/glfs-heal.c | 290 | ||||
-rw-r--r-- | libglusterfs/src/glusterfs.h | 2 | ||||
-rw-r--r-- | tests/basic/afr/self-heald.t | 71 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-common.c | 313 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-inode-read.c | 5 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-data.c | 21 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-entry.c | 24 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal-metadata.c | 6 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr-self-heal.h | 22 | ||||
-rw-r--r-- | xlators/cluster/afr/src/afr.h | 4 |
11 files changed, 498 insertions, 265 deletions
diff --git a/heal/src/Makefile.am b/heal/src/Makefile.am index b4089278607..80be3d443cf 100644 --- a/heal/src/Makefile.am +++ b/heal/src/Makefile.am @@ -6,14 +6,12 @@ glfsheal_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\ $(RLLIBS) $(top_builddir)/rpc/xdr/src/libgfxdr.la \ $(top_builddir)/rpc/rpc-lib/src/libgfrpc.la \ $(top_builddir)/api/src/libgfapi.la \ - $(top_builddir)/xlators/cluster/afr/src/afr.la \ $(GF_GLUSTERFS_LIBS) $(XML_LIBS) glfsheal_LDFLAGS = $(GF_LDFLAGS) AM_CPPFLAGS = $(GF_CPPFLAGS) \ -I$(top_srcdir)/xlators/lib/src\ - -I$(top_srcdir)/xlators/cluster/afr/src\ -I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/rpc-lib/src\ -I$(top_srcdir)/rpc/xdr/src\ -I$(top_srcdir)/api/src\ @@ -30,6 +28,3 @@ CLEANFILES = $(top_builddir)/libglusterfs/src/libglusterfs.la: $(MAKE) -C $(top_builddir)/libglusterfs/src/ all - -$(top_builddir)/xlators/cluster/afr/src/afr.la: - $(MAKE) -C $(top_builddir)/xlators/cluster/afr/src/ all diff --git a/heal/src/glfs-heal.c b/heal/src/glfs-heal.c index 9416316458d..f1249ec6670 100644 --- a/heal/src/glfs-heal.c +++ b/heal/src/glfs-heal.c @@ -17,9 +17,6 @@ #include "syncop.h" #include <string.h> #include <time.h> -#include "afr.h" -#include "afr-self-heal.h" -#include "afr-self-heald.h" #define DEFAULT_HEAL_LOG_FILE_DIRECTORY DATADIR "/log/glusterfs" @@ -88,198 +85,105 @@ out: return ret; } -int -afr_selfheal_locked_metadata_inspect (call_frame_t *frame, xlator_t *this, - inode_t *inode, - gf_boolean_t *metadata_selfheal) +static xlator_t* +_get_afr_ancestor (xlator_t *xl) { - int ret = -1; - unsigned char *locked_on = NULL; - afr_private_t *priv = this->private; - - locked_on = alloca0 (priv->child_count); - - ret = afr_selfheal_inodelk (frame, this, inode, this->name, - LLONG_MAX - 1, 0, locked_on); - { - if (ret == 0) { - /* Not a single lock */ - ret = -afr_final_errno (frame->local, priv); - if (ret == 0) - ret = -ENOTCONN;/* all invalid responses */ - goto out; - } - ret = afr_selfheal_unlocked_inspect (frame, this, inode->gfid, - NULL, NULL, - metadata_selfheal, NULL); - } - afr_selfheal_uninodelk (frame, this, inode, this->name, - LLONG_MAX - 1, 0, locked_on); -out: - return ret; -} + if (!xl || !xl->parents) + return NULL; -int -afr_selfheal_locked_data_inspect (call_frame_t *frame, xlator_t *this, - inode_t *inode, gf_boolean_t *data_selfheal) -{ - int ret = -1; - afr_private_t *priv = NULL; - unsigned char *locked_on = NULL; - unsigned char *data_lock = NULL; - - priv = this->private; - locked_on = alloca0 (priv->child_count); - data_lock = alloca0 (priv->child_count); - - ret = afr_selfheal_tryinodelk (frame, this, inode, priv->sh_domain, - 0, 0, locked_on); - { - if (ret == 0) { - ret = -afr_final_errno (frame->local, priv); - if (ret == 0) - ret = -ENOTCONN;/* all invalid responses */ - goto out; - } - ret = afr_selfheal_inodelk (frame, this, inode, this->name, - 0, 0, data_lock); - { - if (ret == 0) { - ret = -afr_final_errno (frame->local, priv); - if (ret == 0) - ret = -ENOTCONN; - /* all invalid responses */ - goto unlock; - } - ret = afr_selfheal_unlocked_inspect (frame, this, - inode->gfid, NULL, - data_selfheal, - NULL, NULL); - } - afr_selfheal_uninodelk (frame, this, inode, this->name, 0, 0, - data_lock); + while (xl->parents) { + xl = xl->parents->xlator; + if (!xl) + break; + if (strcmp (xl->type, "cluster/replicate") == 0) + return xl; } -unlock: - afr_selfheal_uninodelk (frame, this, inode, priv->sh_domain, 0, 0, - locked_on); -out: - return ret; + + return NULL; } int -afr_selfheal_locked_entry_inspect (call_frame_t *frame, xlator_t *this, - inode_t *inode, gf_boolean_t *entry_selfheal) +glfsh_index_purge (xlator_t *subvol, inode_t *inode, char *name) { - int ret = -1; - afr_private_t *priv = NULL; - unsigned char *locked_on = NULL; - unsigned char *data_lock = NULL; - - priv = this->private; - locked_on = alloca0 (priv->child_count); - data_lock = alloca0 (priv->child_count); - - ret = afr_selfheal_tryentrylk (frame, this, inode, priv->sh_domain, - NULL, locked_on); - { - if (ret == 0) { - ret = -afr_final_errno (frame->local, priv); - if (ret == 0) - ret = -ENOTCONN;/* all invalid responses */ - goto out; - } + loc_t loc = {0, }; + int ret = 0; - ret = afr_selfheal_entrylk (frame, this, inode, this->name, - NULL, data_lock); - { - if (ret == 0) { - ret = -afr_final_errno (frame->local, priv); - if (ret == 0) - ret = -ENOTCONN; - /* all invalid responses */ - goto unlock; - } - ret = afr_selfheal_unlocked_inspect (frame, this, - inode->gfid, - NULL, NULL, NULL, - entry_selfheal); - } - afr_selfheal_unentrylk (frame, this, inode, this->name, NULL, - data_lock); - } -unlock: - afr_selfheal_unentrylk (frame, this, inode, priv->sh_domain, NULL, - locked_on); -out: + loc.parent = inode_ref (inode); + loc.name = name; + + ret = syncop_unlink (subvol, &loc); + + loc_wipe (&loc); return ret; } int -afr_selfheal_locked_inspect (call_frame_t *frame, xlator_t *this, uuid_t gfid, - inode_t **inode, - gf_boolean_t *data_selfheal, - gf_boolean_t *metadata_selfheal, - gf_boolean_t *entry_selfheal) +glfsh_gfid_to_path (xlator_t *this, xlator_t *subvol, uuid_t gfid, char **path_p) { - int ret = -1; - gf_boolean_t dsh = _gf_false; - gf_boolean_t msh = _gf_false; - gf_boolean_t esh = _gf_false; + int ret = 0; + char *path = NULL; + loc_t loc = {0,}; + dict_t *xattr = NULL; - ret = afr_selfheal_unlocked_inspect (frame, this, gfid, inode, - &dsh, &msh, &esh); + uuid_copy (loc.gfid, gfid); + loc.inode = inode_new (this->itable); + + ret = syncop_getxattr (subvol, &loc, &xattr, GFID_TO_PATH_KEY); if (ret) goto out; - /* For every heal type hold locks and check if it indeed needs heal */ - - if (msh) { - msh = _gf_false; - ret = afr_selfheal_locked_metadata_inspect (frame, this, - *inode, &msh); - if (msh || ret < 0) - goto out; + ret = dict_get_str (xattr, GFID_TO_PATH_KEY, &path); + if (ret || !path) { + ret = -EINVAL; + goto out; } - if (dsh) { - dsh = _gf_false; - ret = afr_selfheal_locked_data_inspect (frame, this, *inode, - &dsh); - if (dsh || ret < 0) - goto out; + *path_p = gf_strdup (path); + if (!*path_p) { + ret = -ENOMEM; + goto out; } - if (esh) { - esh = _gf_false; - ret = afr_selfheal_locked_entry_inspect (frame, this, *inode, - &esh); - } + ret = 0; out: - if (entry_selfheal) - *entry_selfheal = esh; - if (data_selfheal) - *data_selfheal = dsh; - if (metadata_selfheal) - *metadata_selfheal = msh; + if (xattr) + dict_unref (xattr); + loc_wipe (&loc); + return ret; } -static xlator_t* -_get_afr_ancestor (xlator_t *xl) +void +glfsh_print_heal_status (dict_t *dict, char *path, uuid_t gfid, + uint64_t *num_entries) { - if (!xl || !xl->parents) - return NULL; - - while (xl->parents) { - xl = xl->parents->xlator; - if (!xl) - break; - if (strcmp (xl->type, "cluster/replicate") == 0) - return xl; - } - - return NULL; + char *value = NULL; + int ret = 0; + char *status = NULL; + + ret = dict_get_str (dict, "heal-info", &value); + if (ret || (!strcmp (value, "no-heal"))) + return; + + (*num_entries)++; + if (!strcmp (value, "heal")) { + ret = gf_asprintf (&status, " "); + } else if (!strcmp (value, "possibly-healing")) { + ret = gf_asprintf (&status, " - Possibly undergoing heal\n"); + } else if (!strcmp (value, "split-brain")) { + ret = gf_asprintf (&status, " - Is in split-brain\n"); + } + if (ret == -1) + status = NULL; + + printf ("%s%s\n", + path ? path : uuid_utoa (gfid), + status); + + if (status) + GF_FREE (status); + return; } static int @@ -291,19 +195,10 @@ glfsh_process_entries (xlator_t *xl, fd_t *fd, gf_dirent_t *entries, int ret = 0; char *path = NULL; uuid_t gfid = {0}; - inode_t *inode = NULL; - call_frame_t *frame = NULL; xlator_t *this = NULL; - gf_boolean_t data_selfheal = _gf_false; - gf_boolean_t metadata_selfheal = _gf_false; - gf_boolean_t entry_selfheal = _gf_false; - + dict_t *dict = NULL; + loc_t loc = {0,}; this = THIS; - frame = afr_frame_create (this); - if (!frame) { - ret = -1; - goto out; - } list_for_each_entry_safe (entry, tmp, &entries->list, list) { *offset = entry->d_off; @@ -314,44 +209,25 @@ glfsh_process_entries (xlator_t *xl, fd_t *fd, gf_dirent_t *entries, uuid_clear (gfid); GF_FREE (path); path = NULL; - if (inode) { - inode_forget (inode, 1); - inode_unref (inode); - inode = NULL; - } - AFR_STACK_RESET (frame); uuid_parse (entry->d_name, gfid); - ret = afr_selfheal_locked_inspect (frame, this, gfid, &inode, - &data_selfheal, - &metadata_selfheal, - &entry_selfheal); - if (ret == 0) { - if (!entry_selfheal && !metadata_selfheal && - !data_selfheal) - continue; - } + uuid_copy (loc.gfid, gfid); + ret = syncop_getxattr (this, &loc, &dict, GF_AFR_HEAL_INFO); + if (ret) + continue; - ret = afr_shd_gfid_to_path (this, xl, gfid, &path); + ret = glfsh_gfid_to_path (this, xl, gfid, &path); if (ret == -ENOENT || ret == -ESTALE) { - afr_shd_index_purge (xl, fd->inode, entry->d_name); + glfsh_index_purge (xl, fd->inode, entry->d_name); ret = 0; continue; } - - (*num_entries)++; - printf ("%s\n", path ? path : uuid_utoa (inode->gfid)); + if (dict) + glfsh_print_heal_status (dict, path, gfid, + num_entries); } ret = 0; -out: - if (inode) { - inode_forget (inode, 1); - inode_unref (inode); - } - - if (frame) - AFR_STACK_DESTROY (frame); GF_FREE (path); return ret; } diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h index b0bf3efce03..a0a8befc447 100644 --- a/libglusterfs/src/glusterfs.h +++ b/libglusterfs/src/glusterfs.h @@ -136,6 +136,8 @@ #define GF_XATTROP_INDEX_GFID "glusterfs.xattrop_index_gfid" #define GF_XATTROP_INDEX_COUNT "glusterfs.xattrop_index_count" +#define GF_AFR_HEAL_INFO "glusterfs.heal-info" + #define GF_GFIDLESS_LOOKUP "gfidless-lookup" /* replace-brick and pump related internal xattrs */ #define RB_PUMP_CMD_START "glusterfs.pump.start" diff --git a/tests/basic/afr/self-heald.t b/tests/basic/afr/self-heald.t index 6937cf227d7..966972e5443 100644 --- a/tests/basic/afr/self-heald.t +++ b/tests/basic/afr/self-heald.t @@ -6,12 +6,43 @@ cleanup; START_TIMESTAMP=`date +%s` +function kill_multiple_bricks { + local vol=$1 + local host=$2 + local brickpath=$3 + + if [ $decide_kill == 0 ] + then + for ((i=0; i<=4; i=i+2)) do + TEST kill_brick $vol $host $brickpath/${vol}$i + done + else + for ((i=1; i<=5; i=i+2)) do + TEST kill_brick $vol $host $brickpath/${vol}$i + done + fi +} +function check_bricks_up { + local vol=$1 + if [ $decide_kill == 0 ] + then + for ((i=0; i<=4; i=i+2)) do + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_in_shd $vol $i + done + else + for ((i=1; i<=5; i=i+2)) do + EXPECT_WITHIN $PROCESS_UP_TIMEOUT "1" afr_child_up_status_in_shd $vol $i + done + fi +} + function disconnected_brick_count { local vol=$1 $CLI volume heal $vol info | \ egrep -i '(transport|Socket is not connected)' | wc -l } +TESTS_EXPECTED_IN_LOOP=20 TEST glusterd TEST pidof glusterd TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{0,1,2,3,4,5} @@ -19,9 +50,10 @@ TEST $CLI volume set $V0 cluster.background-self-heal-count 0 TEST $CLI volume set $V0 cluster.eager-lock off TEST $CLI volume start $V0 TEST glusterfs --volfile-id=/$V0 --volfile-server=$H0 $M0 --attribute-timeout=0 --entry-timeout=0 -TEST kill_brick $V0 $H0 $B0/${V0}0 -TEST kill_brick $V0 $H0 $B0/${V0}2 -TEST kill_brick $V0 $H0 $B0/${V0}4 + +decide_kill=$((`date +"%j"`))%2 + +kill_multiple_bricks $V0 $H0 $B0 cd $M0 HEAL_FILES=0 for i in {1..10} @@ -61,9 +93,9 @@ TEST ! $CLI volume heal $V0 full TEST $CLI volume start $V0 force TEST $CLI volume set $V0 cluster.self-heal-daemon on EXPECT_WITHIN 20 "Y" glustershd_up_status -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 0 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 2 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 4 + +check_bricks_up $V0 + TEST $CLI volume heal $V0 sleep 5 #Until the heal-statistics command implementation #check that this heals the contents partially @@ -98,16 +130,13 @@ TEST mkdir $M0/d #DATA TEST $CLI volume set $V0 cluster.data-self-heal off EXPECT "off" volume_option $V0 cluster.data-self-heal -TEST kill_brick $V0 $H0 $B0/${V0}0 -TEST kill_brick $V0 $H0 $B0/${V0}2 -TEST kill_brick $V0 $H0 $B0/${V0}4 +kill_multiple_bricks $V0 $H0 $B0 echo abc > $M0/f EXPECT 1 afr_get_pending_heal_count $V0 TEST $CLI volume start $V0 force EXPECT_WITHIN 20 "Y" glustershd_up_status -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 0 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 2 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 4 +check_bricks_up $V0 + TEST $CLI volume heal $V0 EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 TEST $CLI volume set $V0 cluster.data-self-heal on @@ -115,16 +144,14 @@ TEST $CLI volume set $V0 cluster.data-self-heal on #METADATA TEST $CLI volume set $V0 cluster.metadata-self-heal off EXPECT "off" volume_option $V0 cluster.metadata-self-heal -TEST kill_brick $V0 $H0 $B0/${V0}0 -TEST kill_brick $V0 $H0 $B0/${V0}2 -TEST kill_brick $V0 $H0 $B0/${V0}4 +kill_multiple_bricks $V0 $H0 $B0 + TEST chmod 777 $M0/f EXPECT 1 afr_get_pending_heal_count $V0 TEST $CLI volume start $V0 force EXPECT_WITHIN 20 "Y" glustershd_up_status -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 0 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 2 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 4 +check_bricks_up $V0 + TEST $CLI volume heal $V0 EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 TEST $CLI volume set $V0 cluster.metadata-self-heal on @@ -132,9 +159,7 @@ TEST $CLI volume set $V0 cluster.metadata-self-heal on #ENTRY TEST $CLI volume set $V0 cluster.entry-self-heal off EXPECT "off" volume_option $V0 cluster.entry-self-heal -TEST kill_brick $V0 $H0 $B0/${V0}0 -TEST kill_brick $V0 $H0 $B0/${V0}2 -TEST kill_brick $V0 $H0 $B0/${V0}4 +kill_multiple_bricks $V0 $H0 $B0 TEST touch $M0/d/a # 4 if mtime/ctime is modified for d in bricks without a # 2 otherwise @@ -142,9 +167,7 @@ PENDING=$( afr_get_pending_heal_count $V0 ) TEST test $PENDING -eq 2 -o $PENDING -eq 4 TEST $CLI volume start $V0 force EXPECT_WITHIN 20 "Y" glustershd_up_status -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 0 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 2 -EXPECT_WITHIN 20 "1" afr_child_up_status_in_shd $V0 4 +check_bricks_up $V0 TEST $CLI volume heal $V0 EXPECT_WITHIN 30 "0" afr_get_pending_heal_count $V0 TEST $CLI volume set $V0 cluster.entry-self-heal on diff --git a/xlators/cluster/afr/src/afr-common.c b/xlators/cluster/afr/src/afr-common.c index 1527a47f716..aefad8be959 100644 --- a/xlators/cluster/afr/src/afr-common.c +++ b/xlators/cluster/afr/src/afr-common.c @@ -494,7 +494,6 @@ afr_selfheal_enabled (xlator_t *this) } - int afr_inode_refresh_done (call_frame_t *frame, xlator_t *this) { @@ -4032,3 +4031,315 @@ afr_mark_pending_changelog (afr_private_t *priv, unsigned char *pending, out: return changelog; } + +gf_boolean_t +afr_decide_heal_info (afr_private_t *priv, unsigned char *sources, int ret) +{ + int sources_count = 0; + + if (ret) + goto out; + + sources_count = AFR_COUNT (sources, priv->child_count); + if (sources_count == priv->child_count) + return _gf_false; +out: + return _gf_true; +} + +int +afr_selfheal_locked_metadata_inspect (call_frame_t *frame, xlator_t *this, + inode_t *inode, gf_boolean_t *msh) +{ + int ret = -1; + unsigned char *locked_on = NULL; + unsigned char *sources = NULL; + unsigned char *sinks = NULL; + unsigned char *healed_sinks = NULL; + struct afr_reply *locked_replies = NULL; + + afr_private_t *priv = this->private; + + locked_on = alloca0 (priv->child_count); + sources = alloca0 (priv->child_count); + sinks = alloca0 (priv->child_count); + healed_sinks = alloca0 (priv->child_count); + + locked_replies = alloca0 (sizeof (*locked_replies) * priv->child_count); + + ret = afr_selfheal_inodelk (frame, this, inode, this->name, + LLONG_MAX - 1, 0, locked_on); + { + if (ret == 0) { + /* Not a single lock */ + ret = -afr_final_errno (frame->local, priv); + if (ret == 0) + ret = -ENOTCONN;/* all invalid responses */ + goto out; + } + ret = __afr_selfheal_metadata_prepare (frame, this, inode, + locked_on, sources, + sinks, healed_sinks, + locked_replies); + *msh = afr_decide_heal_info (priv, sources, ret); + } + afr_selfheal_uninodelk (frame, this, inode, this->name, + LLONG_MAX - 1, 0, locked_on); +out: + if (locked_replies) + afr_replies_wipe (locked_replies, priv->child_count); + return ret; +} + +int +afr_selfheal_locked_data_inspect (call_frame_t *frame, xlator_t *this, + inode_t *inode, gf_boolean_t *dsh) +{ + int ret = -1; + afr_private_t *priv = NULL; + unsigned char *locked_on = NULL; + unsigned char *data_lock = NULL; + unsigned char *sources = NULL; + unsigned char *sinks = NULL; + unsigned char *healed_sinks = NULL; + struct afr_reply *locked_replies = NULL; + + priv = this->private; + locked_on = alloca0 (priv->child_count); + data_lock = alloca0 (priv->child_count); + sources = alloca0 (priv->child_count); + sinks = alloca0 (priv->child_count); + healed_sinks = alloca0 (priv->child_count); + + locked_replies = alloca0 (sizeof (*locked_replies) * priv->child_count); + + ret = afr_selfheal_tryinodelk (frame, this, inode, priv->sh_domain, + 0, 0, locked_on); + { + if (ret == 0) { + ret = -afr_final_errno (frame->local, priv); + if (ret == 0) + ret = -ENOTCONN;/* all invalid responses */ + goto out; + } + ret = afr_selfheal_inodelk (frame, this, inode, this->name, + 0, 0, data_lock); + { + if (ret == 0) { + ret = -afr_final_errno (frame->local, priv); + if (ret == 0) + ret = -ENOTCONN; + /* all invalid responses */ + goto unlock; + } + ret = __afr_selfheal_data_prepare (frame, this, inode, + data_lock, sources, + sinks, healed_sinks, + locked_replies); + *dsh = afr_decide_heal_info (priv, sources, ret); + } + afr_selfheal_uninodelk (frame, this, inode, this->name, 0, 0, + data_lock); + } +unlock: + afr_selfheal_uninodelk (frame, this, inode, priv->sh_domain, 0, 0, + locked_on); +out: + if (locked_replies) + afr_replies_wipe (locked_replies, priv->child_count); + return ret; +} + +int +afr_selfheal_locked_entry_inspect (call_frame_t *frame, xlator_t *this, + inode_t *inode, + gf_boolean_t *esh) +{ + int ret = -1; + int source = -1; + afr_private_t *priv = NULL; + unsigned char *locked_on = NULL; + unsigned char *data_lock = NULL; + unsigned char *sources = NULL; + unsigned char *sinks = NULL; + unsigned char *healed_sinks = NULL; + struct afr_reply *locked_replies = NULL; + + priv = this->private; + locked_on = alloca0 (priv->child_count); + data_lock = alloca0 (priv->child_count); + sources = alloca0 (priv->child_count); + sinks = alloca0 (priv->child_count); + healed_sinks = alloca0 (priv->child_count); + + locked_replies = alloca0 (sizeof (*locked_replies) * priv->child_count); + + ret = afr_selfheal_tryentrylk (frame, this, inode, priv->sh_domain, + NULL, locked_on); + { + if (ret == 0) { + ret = -afr_final_errno (frame->local, priv); + if (ret == 0) + ret = -ENOTCONN;/* all invalid responses */ + goto out; + } + + ret = afr_selfheal_entrylk (frame, this, inode, this->name, + NULL, data_lock); + { + if (ret == 0) { + ret = -afr_final_errno (frame->local, priv); + if (ret == 0) + ret = -ENOTCONN; + /* all invalid responses */ + goto unlock; + } + ret = __afr_selfheal_entry_prepare (frame, this, inode, + data_lock, sources, + sinks, healed_sinks, + locked_replies, + &source); + if ((ret == 0) && source < 0) + ret = -EIO; + *esh = afr_decide_heal_info (priv, sources, ret); + } + afr_selfheal_unentrylk (frame, this, inode, this->name, NULL, + data_lock); + } +unlock: + afr_selfheal_unentrylk (frame, this, inode, priv->sh_domain, NULL, + locked_on); +out: + if (locked_replies) + afr_replies_wipe (locked_replies, priv->child_count); + return ret; +} + +int +afr_selfheal_locked_inspect (call_frame_t *frame, xlator_t *this, uuid_t gfid, + inode_t **inode, + gf_boolean_t *entry_selfheal, + gf_boolean_t *data_selfheal, + gf_boolean_t *metadata_selfheal) + +{ + int ret = -1; + gf_boolean_t dsh = _gf_false; + gf_boolean_t msh = _gf_false; + gf_boolean_t esh = _gf_false; + + ret = afr_selfheal_unlocked_inspect (frame, this, gfid, inode, + &dsh, &msh, &esh); + if (ret) + goto out; + + /* For every heal type hold locks and check if it indeed needs heal */ + + if (msh) { + ret = afr_selfheal_locked_metadata_inspect (frame, this, + *inode, &msh); + if (ret == -EIO) + goto out; + } + + if (dsh) { + ret = afr_selfheal_locked_data_inspect (frame, this, *inode, + &dsh); + if (ret == -EIO || (ret == -EAGAIN)) + goto out; + } + + if (esh) { + ret = afr_selfheal_locked_entry_inspect (frame, this, *inode, + &esh); + } + +out: + *data_selfheal = dsh; + *entry_selfheal = esh; + *metadata_selfheal = msh; + return ret; +} + +dict_t* +afr_set_heal_info (char *status) +{ + dict_t *dict = NULL; + int ret = -1; + + dict = dict_new (); + if (!dict) { + ret = -ENOMEM; + goto out; + } + + if (!strcmp (status, "heal")) { + ret = dict_set_str (dict, "heal-info", "heal"); + if (ret) + gf_log ("", GF_LOG_WARNING, + "Failed to set heal-info key to" + "heal"); + } else if (!strcmp (status, "split-brain")) { + ret = dict_set_str (dict, "heal-info", "split-brain"); + if (ret) + gf_log ("", GF_LOG_WARNING, + "Failed to set heal-info key to" + "split-brain"); + } else if (!strcmp (status, "possibly-healing")) { + ret = dict_set_str (dict, "heal-info", "possibly-healing"); + if (ret) + gf_log ("", GF_LOG_WARNING, + "Failed to set heal-info key to" + "possibly-healing"); + } +out: + return dict; +} + +int +afr_get_heal_info (call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata) +{ + gf_boolean_t data_selfheal = _gf_false; + gf_boolean_t metadata_selfheal = _gf_false; + gf_boolean_t entry_selfheal = _gf_false; + dict_t *dict = NULL; + int ret = -1; + int op_errno = 0; + inode_t *inode = NULL; + + ret = afr_selfheal_locked_inspect (frame, this, loc->gfid, &inode, + &entry_selfheal, + &data_selfheal, &metadata_selfheal); + + if (ret == -ENOMEM) { + op_errno = -ret; + ret = -1; + goto out; + } + + if (ret == -EIO) { + dict = afr_set_heal_info ("split-brain"); + } else if (ret == -EAGAIN) { + dict = afr_set_heal_info ("possibly-healing"); + } else if (ret == 0) { + if (!data_selfheal && !entry_selfheal && + !metadata_selfheal) { + dict = afr_set_heal_info ("no-heal"); + } else { + dict = afr_set_heal_info ("heal"); + } + } else if (ret < 0) { + if (data_selfheal || entry_selfheal || + metadata_selfheal) { + dict = afr_set_heal_info ("heal"); + } + } + ret = 0; + +out: + AFR_STACK_UNWIND (getxattr, frame, ret, op_errno, dict, NULL); + if (dict) + dict_unref (dict); + return ret; +} diff --git a/xlators/cluster/afr/src/afr-inode-read.c b/xlators/cluster/afr/src/afr-inode-read.c index 4cb219246f7..210d710a2b3 100644 --- a/xlators/cluster/afr/src/afr-inode-read.c +++ b/xlators/cluster/afr/src/afr-inode-read.c @@ -1373,6 +1373,11 @@ afr_getxattr (call_frame_t *frame, xlator_t *this, return 0; } + if (!strcmp (name, GF_AFR_HEAL_INFO)) { + afr_get_heal_info (frame, this, loc, xdata); + return 0; + } + /* * if we are doing getxattr with pathinfo as the key then we * collect information from all childs diff --git a/xlators/cluster/afr/src/afr-self-heal-data.c b/xlators/cluster/afr/src/afr-self-heal-data.c index f7503faa719..0a43d128634 100644 --- a/xlators/cluster/afr/src/afr-self-heal-data.c +++ b/xlators/cluster/afr/src/afr-self-heal-data.c @@ -569,10 +569,11 @@ out: * The return value is the index of the subvolume to be used as the source * for self-healing, or -1 if no healing is necessary/split brain. */ -static int -__afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd, - unsigned char *locked_on, unsigned char *sources, - unsigned char *sinks, unsigned char *healed_sinks, +int +__afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, + inode_t *inode, unsigned char *locked_on, + unsigned char *sources, unsigned char *sinks, + unsigned char *healed_sinks, struct afr_reply *replies) { int ret = -1; @@ -582,10 +583,8 @@ __afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd, priv = this->private; - ret = afr_selfheal_unlocked_discover (frame, fd->inode, fd->inode->gfid, + ret = afr_selfheal_unlocked_discover (frame, inode, inode->gfid, replies); - if (ret) - return ret; witness = alloca0(priv->child_count * sizeof (*witness)); ret = afr_selfheal_find_direction (frame, this, replies, @@ -650,8 +649,9 @@ __afr_selfheal_data (call_frame_t *frame, xlator_t *this, fd_t *fd, goto unlock; } - ret = __afr_selfheal_data_prepare (frame, this, fd, data_lock, - sources, sinks, healed_sinks, + ret = __afr_selfheal_data_prepare (frame, this, fd->inode, + data_lock, sources, sinks, + healed_sinks, locked_replies); if (ret < 0) goto unlock; @@ -678,7 +678,7 @@ __afr_selfheal_data (call_frame_t *frame, xlator_t *this, fd_t *fd, unlock: afr_selfheal_uninodelk (frame, this, fd->inode, this->name, 0, 0, data_lock); - if (ret < 0) + if (ret < 0) goto out; ret = afr_selfheal_data_do (frame, this, fd, source, healed_sinks, @@ -731,7 +731,6 @@ afr_selfheal_data_open (xlator_t *this, inode_t *inode) return fd; } - int afr_selfheal_data (call_frame_t *frame, xlator_t *this, inode_t *inode) { diff --git a/xlators/cluster/afr/src/afr-self-heal-entry.c b/xlators/cluster/afr/src/afr-self-heal-entry.c index 3f753251e7c..63ac61bce31 100644 --- a/xlators/cluster/afr/src/afr-self-heal-entry.c +++ b/xlators/cluster/afr/src/afr-self-heal-entry.c @@ -357,11 +357,11 @@ __afr_selfheal_entry_finalize_source (xlator_t *this, unsigned char *sources, return source; } - -static int -__afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd, - unsigned char *locked_on, unsigned char *sources, - unsigned char *sinks, unsigned char *healed_sinks, +int +__afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, + inode_t *inode, unsigned char *locked_on, + unsigned char *sources, unsigned char *sinks, + unsigned char *healed_sinks, struct afr_reply *replies, int *source_p) { int ret = -1; @@ -371,11 +371,8 @@ __afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd, priv = this->private; - ret = afr_selfheal_unlocked_discover (frame, fd->inode, fd->inode->gfid, + ret = afr_selfheal_unlocked_discover (frame, inode, inode->gfid, replies); - if (ret) - return ret; - witness = alloca0 (sizeof (*witness) * priv->child_count); ret = afr_selfheal_find_direction (frame, this, replies, AFR_ENTRY_TRANSACTION, @@ -407,7 +404,6 @@ __afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, fd_t *fd, return ret; } - static int afr_selfheal_entry_dirent (call_frame_t *frame, xlator_t *this, fd_t *fd, char *name) @@ -445,7 +441,8 @@ afr_selfheal_entry_dirent (call_frame_t *frame, xlator_t *this, goto unlock; } - ret = __afr_selfheal_entry_prepare (frame, this, fd, locked_on, + ret = __afr_selfheal_entry_prepare (frame, this, fd->inode, + locked_on, sources, sinks, healed_sinks, par_replies, &source); @@ -593,8 +590,9 @@ __afr_selfheal_entry (call_frame_t *frame, xlator_t *this, fd_t *fd, goto unlock; } - ret = __afr_selfheal_entry_prepare (frame, this, fd, data_lock, - sources, sinks, healed_sinks, + ret = __afr_selfheal_entry_prepare (frame, this, fd->inode, + data_lock, sources, sinks, + healed_sinks, locked_replies, &source); } unlock: diff --git a/xlators/cluster/afr/src/afr-self-heal-metadata.c b/xlators/cluster/afr/src/afr-self-heal-metadata.c index 87600df3bad..c09f19ac5fd 100644 --- a/xlators/cluster/afr/src/afr-self-heal-metadata.c +++ b/xlators/cluster/afr/src/afr-self-heal-metadata.c @@ -294,7 +294,8 @@ __afr_selfheal_metadata_finalize_source (call_frame_t *frame, xlator_t *this, return source; } -static int + +int __afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, inode_t *inode, unsigned char *locked_on, unsigned char *sources, unsigned char *sinks, unsigned char *healed_sinks, @@ -310,9 +311,6 @@ __afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, inode_t *i ret = afr_selfheal_unlocked_discover (frame, inode, inode->gfid, replies); - if (ret) - return ret; - witness = alloca0 (sizeof (*witness) * priv->child_count); ret = afr_selfheal_find_direction (frame, this, replies, AFR_METADATA_TRANSACTION, diff --git a/xlators/cluster/afr/src/afr-self-heal.h b/xlators/cluster/afr/src/afr-self-heal.h index bb3f0e7029f..50cff91ccb3 100644 --- a/xlators/cluster/afr/src/afr-self-heal.h +++ b/xlators/cluster/afr/src/afr-self-heal.h @@ -200,6 +200,28 @@ gf_boolean_t afr_does_witness_exist (xlator_t *this, uint64_t *witness); int +__afr_selfheal_data_prepare (call_frame_t *frame, xlator_t *this, + inode_t *inode, unsigned char *locked_on, + unsigned char *sources, + unsigned char *sinks, unsigned char *healed_sinks, + struct afr_reply *replies); + +int +__afr_selfheal_metadata_prepare (call_frame_t *frame, xlator_t *this, + inode_t *inode, unsigned char *locked_on, + unsigned char *sources, + unsigned char *sinks, + unsigned char *healed_sinks, + struct afr_reply *replies); +int +__afr_selfheal_entry_prepare (call_frame_t *frame, xlator_t *this, + inode_t *inode, unsigned char *locked_on, + unsigned char *sources, + unsigned char *sinks, + unsigned char *healed_sinks, + struct afr_reply *replies, int *source_p); + +int afr_selfheal_unlocked_inspect (call_frame_t *frame, xlator_t *this, uuid_t gfid, inode_t **link_inode, gf_boolean_t *data_selfheal, diff --git a/xlators/cluster/afr/src/afr.h b/xlators/cluster/afr/src/afr.h index 51e57e8207f..7e138c54ec0 100644 --- a/xlators/cluster/afr/src/afr.h +++ b/xlators/cluster/afr/src/afr.h @@ -1011,4 +1011,8 @@ afr_xattrs_are_equal (dict_t *dict1, dict_t *dict2); gf_boolean_t afr_is_xattr_ignorable (char *key); + +int +afr_get_heal_info (call_frame_t *frame, xlator_t *this, loc_t *loc, + dict_t *xdata); #endif /* __AFR_H__ */ |