summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libglusterfs/src/syncop-utils.c35
-rw-r--r--libglusterfs/src/syncop-utils.h4
-rw-r--r--tests/afr.rc5
-rw-r--r--tests/basic/ec/ec-background-heals.t6
-rw-r--r--tests/volume.rc5
-rw-r--r--xlators/cluster/afr/src/afr-self-heald.c27
-rw-r--r--xlators/cluster/ec/src/ec-common.h3
-rw-r--r--xlators/cluster/ec/src/ec-heal.c254
-rw-r--r--xlators/cluster/ec/src/ec-heald.c46
-rw-r--r--xlators/cluster/ec/src/ec.c10
10 files changed, 309 insertions, 86 deletions
diff --git a/libglusterfs/src/syncop-utils.c b/libglusterfs/src/syncop-utils.c
index 029f10b058e..fa9e6a28768 100644
--- a/libglusterfs/src/syncop-utils.c
+++ b/libglusterfs/src/syncop-utils.c
@@ -591,3 +591,38 @@ out:
return ret;
}
+
+int
+syncop_inode_find (xlator_t *this, xlator_t *subvol,
+ uuid_t gfid, inode_t **inode,
+ dict_t *xdata, dict_t **rsp_dict)
+{
+ int ret = 0;
+ loc_t loc = {0, };
+ struct iatt iatt = {0, };
+ *inode = NULL;
+
+ *inode = inode_find (this->itable, gfid);
+ if (*inode)
+ goto out;
+
+ loc.inode = inode_new (this->itable);
+ if (!loc.inode) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ gf_uuid_copy (loc.gfid, gfid);
+
+ ret = syncop_lookup (subvol, &loc, &iatt, NULL, xdata, rsp_dict);
+ if (ret < 0)
+ goto out;
+
+ *inode = inode_link (loc.inode, NULL, NULL, &iatt);
+ if (!*inode) {
+ ret = -ENOMEM;
+ goto out;
+ }
+out:
+ loc_wipe (&loc);
+ return ret;
+}
diff --git a/libglusterfs/src/syncop-utils.h b/libglusterfs/src/syncop-utils.h
index 3968d758c6e..4761371c120 100644
--- a/libglusterfs/src/syncop-utils.h
+++ b/libglusterfs/src/syncop-utils.h
@@ -43,4 +43,8 @@ syncop_ftw_throttle (xlator_t *subvol, loc_t *loc, int pid, void *data,
int (*fn) (xlator_t *subvol, gf_dirent_t *entry,
loc_t *parent, void *data),
int count, int sleep_time);
+int
+syncop_inode_find (xlator_t *this, xlator_t *subvol,
+ uuid_t gfid, inode_t **inode,
+ dict_t *xdata, dict_t **rsp_dict);
#endif /* _SYNCOP_H */
diff --git a/tests/afr.rc b/tests/afr.rc
index ed376f0b41f..bdf4075a233 100644
--- a/tests/afr.rc
+++ b/tests/afr.rc
@@ -85,11 +85,6 @@ function is_file_heal_done {
#count the number of entries marked for self-heal
#in brick $1's index
-function count_sh_entries()
-{
- ls $1/.glusterfs/indices/xattrop | grep -v "xattrop-" | wc -l
-}
-
function count_index_entries()
{
ls $1/.glusterfs/indices/xattrop | wc -l
diff --git a/tests/basic/ec/ec-background-heals.t b/tests/basic/ec/ec-background-heals.t
index 7ac6c0efc12..eb434908bad 100644
--- a/tests/basic/ec/ec-background-heals.t
+++ b/tests/basic/ec/ec-background-heals.t
@@ -23,7 +23,10 @@ EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0
EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 background-heals
EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "0" mount_get_option_value $M0 $V0-disperse-0 heal-wait-qlength
TEST touch $M0/a
-EXPECT_WITHIN $CHILD_UP_TIMEOUT "0" get_pending_heal_count $V0 #One for each active brick
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}0
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}1
+EXPECT_WITHIN $HEAL_TIMEOUT "^0$" count_sh_entries $B0/${V0}2
+
TEST kill_brick $V0 $H0 $B0/${V0}2
echo abc > $M0/a
EXPECT 2 get_pending_heal_count $V0 #One for each active brick
@@ -31,7 +34,6 @@ $CLI volume start $V0 force
EXPECT_WITHIN $CHILD_UP_TIMEOUT "3" ec_child_up_count $V0 0
#Accessing file shouldn't heal the file
EXPECT "abc" cat $M0/a
-sleep 3
EXPECT 2 get_pending_heal_count $V0 #One for each active brick
TEST $CLI volume set $V0 disperse.background-heals 1
EXPECT_WITHIN $CONFIG_UPDATE_TIMEOUT "1" mount_get_option_value $M0 $V0-disperse-0 background-heals
diff --git a/tests/volume.rc b/tests/volume.rc
index f9725b2cba1..8cad822e9ad 100644
--- a/tests/volume.rc
+++ b/tests/volume.rc
@@ -710,3 +710,8 @@ function get_hard_link_count {
local path=$1;
stat -c %h $path
}
+
+function count_sh_entries()
+{
+ ls $1/.glusterfs/indices/xattrop | grep -v "xattrop-" | wc -l
+}
diff --git a/xlators/cluster/afr/src/afr-self-heald.c b/xlators/cluster/afr/src/afr-self-heald.c
index 8a3a5521409..e1a40521709 100644
--- a/xlators/cluster/afr/src/afr-self-heald.c
+++ b/xlators/cluster/afr/src/afr-self-heald.c
@@ -153,22 +153,11 @@ unlock:
inode_t *
afr_shd_inode_find (xlator_t *this, xlator_t *subvol, uuid_t gfid)
{
- int ret = 0;
- uint64_t val = IA_INVAL;
- loc_t loc = {0, };
+ int ret = 0;
+ uint64_t val = IA_INVAL;
dict_t *xdata = NULL;
dict_t *rsp_dict = NULL;
- inode_t *inode = NULL;
- struct iatt iatt = {0, };
-
- inode = inode_find (this->itable, gfid);
- if (inode)
- goto out;
-
- loc.inode = inode_new (this->itable);
- if (!loc.inode)
- goto out;
- gf_uuid_copy (loc.gfid, gfid);
+ inode_t *inode = NULL;
xdata = dict_new ();
if (!xdata)
@@ -178,7 +167,8 @@ afr_shd_inode_find (xlator_t *this, xlator_t *subvol, uuid_t gfid)
if (ret)
goto out;
- ret = syncop_lookup (subvol, &loc, &iatt, NULL, xdata, &rsp_dict);
+ ret = syncop_inode_find (this, subvol, gfid, &inode,
+ xdata, &rsp_dict);
if (ret < 0)
goto out;
@@ -188,15 +178,16 @@ afr_shd_inode_find (xlator_t *this, xlator_t *subvol, uuid_t gfid)
if (ret)
goto out;
}
-
- inode = inode_link (loc.inode, NULL, NULL, &iatt);
ret = inode_ctx_set2 (inode, subvol, 0, &val);
out:
+ if (ret && inode) {
+ inode_unref (inode);
+ inode = NULL;
+ }
if (xdata)
dict_unref (xdata);
if (rsp_dict)
dict_unref (rsp_dict);
- loc_wipe (&loc);
return inode;
}
diff --git a/xlators/cluster/ec/src/ec-common.h b/xlators/cluster/ec/src/ec-common.h
index d720d24adc5..5851b5d57b0 100644
--- a/xlators/cluster/ec/src/ec-common.h
+++ b/xlators/cluster/ec/src/ec-common.h
@@ -118,4 +118,7 @@ void ec_manager(ec_fop_data_t * fop, int32_t error);
gf_boolean_t ec_is_recoverable_error (int32_t op_errno);
void ec_handle_healers_done (ec_fop_data_t *fop);
+int32_t
+ec_get_heal_info (xlator_t *this, loc_t *loc, dict_t **dict);
+
#endif /* __EC_COMMON_H__ */
diff --git a/xlators/cluster/ec/src/ec-heal.c b/xlators/cluster/ec/src/ec-heal.c
index 14255616830..bac8337cd3d 100644
--- a/xlators/cluster/ec/src/ec-heal.c
+++ b/xlators/cluster/ec/src/ec-heal.c
@@ -1489,22 +1489,29 @@ unlock:
return ret;
}
-/*Data heal*/
+/*Find direction for data heal and heal info*/
int
ec_heal_data_find_direction (ec_t *ec, default_args_cbk_t *replies,
- uint64_t *versions, uint64_t *dirty,
- uint64_t *size, unsigned char *sources,
- unsigned char *healed_sinks)
+ uint64_t *data_versions, uint64_t *meta_versions,
+ uint64_t *dirty, uint64_t *size, unsigned char *sources,
+ unsigned char *healed_sinks, int which)
{
uint64_t xattr[EC_VERSION_SIZE] = {0};
- char version_size[64] = {0};
+ char version_size[128] = {0};
dict_t *version_size_db = NULL;
+ uint64_t *m_versions = NULL;
unsigned char *same = NULL;
int max_same_count = 0;
int source = 0;
int i = 0;
int ret = 0;
+ dict_t *dict = NULL;
+ if (!meta_versions) {
+ m_versions = alloca0 (ec->nodes * sizeof (*m_versions));
+ } else {
+ m_versions = meta_versions;
+ }
version_size_db = dict_new ();
if (!version_size_db) {
ret = -ENOMEM;
@@ -1516,23 +1523,31 @@ ec_heal_data_find_direction (ec_t *ec, default_args_cbk_t *replies,
continue;
if (replies[i].op_ret < 0)
continue;
- ret = ec_dict_del_array (replies[i].xattr, EC_XATTR_VERSION,
+ dict = (which == EC_COMBINE_XDATA) ? replies[i].xdata :
+ replies[i].xattr;
+
+ ret = ec_dict_del_array (dict, EC_XATTR_VERSION,
xattr, EC_VERSION_SIZE);
if (ret == 0) {
- versions[i] = xattr[EC_DATA_TXN];
+ data_versions[i] = xattr[EC_DATA_TXN];
+ if (meta_versions) {
+ m_versions[i] = xattr[EC_METADATA_TXN];
+ }
}
memset (xattr, 0, sizeof (xattr));
- ret = ec_dict_del_array (replies[i].xattr, EC_XATTR_DIRTY,
+ ret = ec_dict_del_array (dict, EC_XATTR_DIRTY,
xattr, EC_VERSION_SIZE);
if (ret == 0) {
dirty[i] = xattr[EC_DATA_TXN];
}
- ret = ec_dict_del_number (replies[i].xattr, EC_XATTR_SIZE,
+ ret = ec_dict_del_number (dict, EC_XATTR_SIZE,
&size[i]);
- /*Build a db of same version, size*/
+ /*Build a db of same metadata and data version and size*/
snprintf (version_size, sizeof (version_size),
- "%"PRIu64"-%"PRIu64, versions[i], size[i]);
+ "%"PRIu64"-%"PRIu64"-%"PRIu64, data_versions[i],
+ m_versions[i], size[i]);
+
ret = dict_get_bin (version_size_db, version_size,
(void **)&same);
if (ret < 0) {
@@ -1562,7 +1577,11 @@ ec_heal_data_find_direction (ec_t *ec, default_args_cbk_t *replies,
goto out;
} else {
snprintf (version_size, sizeof (version_size),
- "%"PRIu64"-%"PRIu64, versions[source], size[source]);
+ "%"PRIu64"-%"PRIu64"-%"PRIu64,
+ data_versions[source],
+ m_versions[source],
+ size[source]);
+
ret = dict_get_bin (version_size_db, version_size,
(void **)&same);
if (ret < 0)
@@ -1621,8 +1640,9 @@ __ec_heal_data_prepare (call_frame_t *frame, ec_t *ec, fd_t *fd,
goto out;
}
- source = ec_heal_data_find_direction (ec, replies, versions, dirty,
- size, sources, healed_sinks);
+ source = ec_heal_data_find_direction (ec, replies, versions, NULL,
+ dirty, size, sources,
+ healed_sinks, EC_COMBINE_DICT);
ret = source;
if (ret < 0)
goto out;
@@ -2602,7 +2622,7 @@ out:
int32_t
ec_launch_replace_heal (ec_t *ec)
{
- int ret = -1;
+ int ret = -1;
if (!ec)
return ret;
@@ -2614,3 +2634,207 @@ ec_launch_replace_heal (ec_t *ec)
}
return ret;
}
+
+int32_t
+ec_set_heal_info(dict_t **dict_rsp, char *status)
+{
+ dict_t *dict = NULL;
+ int ret = 0;
+
+ dict = dict_new ();
+ if (!dict) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = dict_set_str (dict, "heal-info", status);
+ if (ret) {
+ gf_msg (THIS->name, GF_LOG_WARNING, -ret,
+ EC_MSG_HEAL_FAIL,
+ "Failed to set heal-info key to "
+ "%s", status);
+ dict_unref(dict);
+ dict = NULL;
+ }
+ *dict_rsp = dict;
+out:
+ return ret;
+}
+
+int32_t
+ec_need_heal (ec_t *ec, default_args_cbk_t *replies, gf_boolean_t *need_heal)
+{
+ uint64_t *dirty = NULL;
+ unsigned char *sources = NULL;
+ unsigned char *healed_sinks = NULL;
+ uint64_t *data_versions = NULL;
+ uint64_t *meta_versions = NULL;
+ uint64_t *size = NULL;
+ int ret = 0;
+ int source_count = 0;
+
+ sources = alloca0(ec->nodes);
+ healed_sinks = alloca0(ec->nodes);
+ dirty = alloca0 (ec->nodes * sizeof (*dirty));
+ size = alloca0 (ec->nodes * sizeof (*size));
+ data_versions = alloca0 (ec->nodes * sizeof (*data_versions));
+ meta_versions = alloca0 (ec->nodes * sizeof (*meta_versions));
+
+ ret = ec_heal_data_find_direction (ec, replies, data_versions,
+ meta_versions, dirty, size,
+ sources, healed_sinks,
+ EC_COMBINE_XDATA);
+ if (ret < 0 && ret != -EIO) {
+ goto out;
+ }
+ source_count = EC_COUNT (sources, ec->nodes);
+ if (source_count != ec->nodes) {
+ *need_heal = _gf_true;
+ }
+ ret = source_count;
+out:
+ return ret;
+}
+
+int32_t
+ec_heal_inspect (call_frame_t *frame, ec_t *ec,
+ inode_t *inode, unsigned char *locked_on,
+ gf_boolean_t *need_heal)
+{
+ loc_t loc = {0};
+ int ret = 0;
+ dict_t *xdata = NULL;
+ uint64_t zero_array[2] = {0};
+ uint64_t zero_value = 0;
+ unsigned char *output = NULL;
+ default_args_cbk_t *replies = NULL;
+
+ EC_REPLIES_ALLOC (replies, ec->nodes);
+ output = alloca0 (ec->nodes);
+
+ loc.inode = inode_ref (inode);
+ gf_uuid_copy (loc.gfid, inode->gfid);
+
+ xdata = dict_new ();
+ if (!xdata ||
+ dict_set_static_bin (xdata, EC_XATTR_VERSION, zero_array,
+ sizeof (zero_array)) ||
+ dict_set_static_bin (xdata, EC_XATTR_DIRTY, zero_array,
+ sizeof (zero_array)) ||
+ dict_set_static_bin (xdata, EC_XATTR_SIZE, &zero_value,
+ sizeof (zero_value))) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = cluster_lookup (ec->xl_list, locked_on, ec->nodes, replies,
+ output, frame, ec->xl, &loc, xdata);
+ if (ret != ec->nodes) {
+ ret = ec->nodes;
+ *need_heal = _gf_true;
+ goto out;
+ }
+ ret = ec_need_heal (ec, replies, need_heal);
+
+out:
+ cluster_replies_wipe (replies, ec->nodes);
+ loc_wipe (&loc);
+ if (xdata) {
+ dict_unref(xdata);
+ }
+ return ret;
+}
+
+int32_t
+ec_heal_locked_inspect (call_frame_t *frame, ec_t *ec, inode_t *inode,
+ gf_boolean_t *need_heal)
+{
+ unsigned char *locked_on = NULL;
+ unsigned char *up_subvols = NULL;
+ unsigned char *output = NULL;
+ default_args_cbk_t *replies = NULL;
+ int ret = 0;
+
+ EC_REPLIES_ALLOC (replies, ec->nodes);
+ locked_on = alloca0(ec->nodes);
+ output = alloca0(ec->nodes);
+ up_subvols = alloca0(ec->nodes);
+ ec_mask_to_char_array (ec->xl_up, up_subvols, ec->nodes);
+
+ ret = cluster_inodelk (ec->xl_list, up_subvols, ec->nodes,
+ replies, locked_on, frame, ec->xl,
+ ec->xl->name, inode, 0, 0);
+ if (ret != ec->nodes) {
+ *need_heal = _gf_true;
+ goto unlock;
+ }
+ ret = ec_heal_inspect (frame, ec, inode,
+ locked_on, need_heal);
+unlock:
+ cluster_uninodelk (ec->xl_list, locked_on, ec->nodes,
+ replies, output, frame, ec->xl,
+ ec->xl->name, inode, 0, 0);
+ cluster_replies_wipe (replies, ec->nodes);
+ return ret;
+}
+
+int32_t
+ec_get_heal_info (xlator_t *this, loc_t *entry_loc, dict_t **dict_rsp)
+{
+ int ret = -ENOMEM;
+ gf_boolean_t need_heal = _gf_false;
+ call_frame_t *frame = NULL;
+ ec_t *ec = NULL;
+ unsigned char *up_subvols = NULL;
+ loc_t loc = {0, };
+
+ VALIDATE_OR_GOTO(this, out);
+ GF_VALIDATE_OR_GOTO(this->name, entry_loc, out);
+
+ ec = this->private;
+ up_subvols = alloca0(ec->nodes);
+ ec_mask_to_char_array (ec->xl_up, up_subvols, ec->nodes);
+
+ frame = create_frame (this, this->ctx->pool);
+ if (!frame) {
+ goto out;
+ }
+ ec_owner_set(frame, frame->root);
+ frame->root->uid = 0;
+ frame->root->gid = 0;
+ frame->root->pid = GF_CLIENT_PID_SELF_HEALD;
+
+ if (loc_copy(&loc, entry_loc) != 0) {
+ gf_msg (this->name, GF_LOG_ERROR,
+ ENOMEM, EC_MSG_LOC_COPY_FAIL,
+ "Failed to copy a location.");
+ goto out;
+ }
+ if (!loc.inode) {
+ ret = syncop_inode_find (this, this, loc.gfid,
+ &loc.inode, NULL, NULL);
+ if (ret < 0)
+ goto out;
+ }
+
+ ret = ec_heal_inspect (frame, ec, loc.inode, up_subvols,
+ &need_heal);
+ if (ret == ec->nodes) {
+ goto set_heal;
+ }
+ need_heal = _gf_false;
+ ret = ec_heal_locked_inspect (frame, ec, loc.inode,
+ &need_heal);
+ if (ret < 0)
+ goto out;
+set_heal:
+ if (need_heal) {
+ ret = ec_set_heal_info (dict_rsp, "heal");
+ } else {
+ ret = ec_set_heal_info (dict_rsp, "no-heal");
+ }
+out:
+ if (frame) {
+ STACK_DESTROY (frame->root);
+ }
+ loc_wipe (&loc);
+ return ret;
+}
diff --git a/xlators/cluster/ec/src/ec-heald.c b/xlators/cluster/ec/src/ec-heald.c
index c87f328db0f..9860f10eadd 100644
--- a/xlators/cluster/ec/src/ec-heald.c
+++ b/xlators/cluster/ec/src/ec-heald.c
@@ -126,42 +126,6 @@ unlock:
return ret;
}
-
-int
-ec_shd_inode_find (xlator_t *this, xlator_t *subvol,
- uuid_t gfid, inode_t **inode)
-{
- int ret = 0;
- loc_t loc = {0, };
- struct iatt iatt = {0, };
- *inode = NULL;
-
- *inode = inode_find (this->itable, gfid);
- if (*inode)
- goto out;
-
- loc.inode = inode_new (this->itable);
- if (!loc.inode) {
- ret = -ENOMEM;
- goto out;
- }
- gf_uuid_copy (loc.gfid, gfid);
-
- ret = syncop_lookup (subvol, &loc, &iatt, NULL, NULL, NULL);
- if (ret < 0)
- goto out;
-
- *inode = inode_link (loc.inode, NULL, NULL, &iatt);
- if (!*inode) {
- ret = -ENOMEM;
- goto out;
- }
-out:
- loc_wipe (&loc);
- return ret;
-}
-
-
int
ec_shd_index_inode (xlator_t *this, xlator_t *subvol, inode_t **inode)
{
@@ -190,7 +154,8 @@ ec_shd_index_inode (xlator_t *this, xlator_t *subvol, inode_t **inode)
gf_msg_debug (this->name, 0, "index-dir gfid for %s: %s",
subvol->name, uuid_utoa (index_gfid));
- ret = ec_shd_inode_find (this, subvol, index_gfid, inode);
+ ret = syncop_inode_find (this, subvol, index_gfid,
+ inode, NULL, NULL);
out:
loc_wipe (&rootloc);
@@ -250,8 +215,8 @@ ec_shd_index_heal (xlator_t *subvol, gf_dirent_t *entry, loc_t *parent,
if (ret < 0)
goto out;
- ret = ec_shd_inode_find (healer->this, healer->this, loc.gfid,
- &loc.inode);
+ ret = syncop_inode_find (healer->this, healer->this, loc.gfid,
+ &loc.inode, NULL, NULL);
if (ret < 0)
goto out;
@@ -329,7 +294,8 @@ ec_shd_full_heal (xlator_t *subvol, gf_dirent_t *entry, loc_t *parent,
if (ret < 0)
goto out;
- ret = ec_shd_inode_find (this, this, loc.gfid, &loc.inode);
+ ret = syncop_inode_find (this, this, loc.gfid,
+ &loc.inode, NULL, NULL);
if (ret < 0)
goto out;
diff --git a/xlators/cluster/ec/src/ec.c b/xlators/cluster/ec/src/ec.c
index dff5a784b2b..e10de4e38aa 100644
--- a/xlators/cluster/ec/src/ec.c
+++ b/xlators/cluster/ec/src/ec.c
@@ -806,13 +806,11 @@ ec_handle_heal_commands (call_frame_t *frame, xlator_t *this, loc_t *loc,
if (!name || strcmp (name, GF_HEAL_INFO))
return -1;
- dict_rsp = dict_new ();
- if (dict_rsp == NULL)
- goto out;
+ op_errno = -ec_get_heal_info (this, loc, &dict_rsp);
+ if (op_errno <= 0) {
+ op_errno = op_ret = 0;
+ }
- if (dict_set_str (dict_rsp, "heal-info", "heal") == 0)
- op_ret = 0;
-out:
STACK_UNWIND_STRICT (getxattr, frame, op_ret, op_errno, dict_rsp, NULL);
if (dict_rsp)
dict_unref (dict_rsp);