summaryrefslogtreecommitdiffstats
path: root/xlators/mgmt/glusterd/src/glusterd-peer-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-peer-utils.c')
-rw-r--r--xlators/mgmt/glusterd/src/glusterd-peer-utils.c151
1 files changed, 94 insertions, 57 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-peer-utils.c b/xlators/mgmt/glusterd/src/glusterd-peer-utils.c
index 3a145264b79..49fab4cb8b9 100644
--- a/xlators/mgmt/glusterd/src/glusterd-peer-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-peer-utils.c
@@ -12,44 +12,21 @@
#include "glusterd-store.h"
#include "common-utils.h"
-int32_t
-glusterd_peerinfo_cleanup (glusterd_peerinfo_t *peerinfo)
-{
- GF_ASSERT (peerinfo);
- glusterd_peerctx_t *peerctx = NULL;
- gf_boolean_t quorum_action = _gf_false;
- glusterd_conf_t *priv = THIS->private;
-
- if (peerinfo->quorum_contrib != QUORUM_NONE)
- quorum_action = _gf_true;
- if (peerinfo->rpc) {
- peerctx = peerinfo->rpc->mydata;
- peerinfo->rpc->mydata = NULL;
- peerinfo->rpc = glusterd_rpc_clnt_unref (priv, peerinfo->rpc);
- peerinfo->rpc = NULL;
- if (peerctx) {
- GF_FREE (peerctx->errstr);
- GF_FREE (peerctx);
- }
- }
- glusterd_peerinfo_destroy (peerinfo);
-
- if (quorum_action)
- glusterd_do_quorum_action ();
- return 0;
-}
-
-int32_t
-glusterd_peerinfo_destroy (glusterd_peerinfo_t *peerinfo)
+void
+glusterd_peerinfo_destroy (struct rcu_head *head)
{
- int32_t ret = -1;
+ int32_t ret = -1;
+ glusterd_peerinfo_t *peerinfo = NULL;
glusterd_peer_hostname_t *hostname = NULL;
- glusterd_peer_hostname_t *tmp = NULL;
+ glusterd_peer_hostname_t *tmp = NULL;
- if (!peerinfo)
- goto out;
+ /* This works as rcu_head is the first member of gd_rcu_head */
+ peerinfo = caa_container_of (head, glusterd_peerinfo_t, head);
+
+ /* Set THIS to the saved this. Needed by some functions below */
+ THIS = peerinfo->head.this;
- cds_list_del_init (&peerinfo->uuid_list);
+ CDS_INIT_LIST_HEAD (&peerinfo->uuid_list);
ret = glusterd_store_delete_peerinfo (peerinfo);
if (ret) {
@@ -65,13 +42,44 @@ glusterd_peerinfo_destroy (glusterd_peerinfo_t *peerinfo)
}
glusterd_sm_tr_log_delete (&peerinfo->sm_log);
+ pthread_mutex_destroy (&peerinfo->delete_lock);
GF_FREE (peerinfo);
+
peerinfo = NULL;
- ret = 0;
+ return;
+}
-out:
- return ret;
+int32_t
+glusterd_peerinfo_cleanup (glusterd_peerinfo_t *peerinfo)
+{
+ GF_ASSERT (peerinfo);
+ glusterd_peerctx_t *peerctx = NULL;
+ gf_boolean_t quorum_action = _gf_false;
+ glusterd_conf_t *priv = THIS->private;
+
+ if (pthread_mutex_trylock (&peerinfo->delete_lock)) {
+ /* Someone else is already deleting the peer, so give up */
+ return 0;
+ }
+
+ uatomic_set (&peerinfo->deleting, _gf_true);
+
+ if (peerinfo->quorum_contrib != QUORUM_NONE)
+ quorum_action = _gf_true;
+ if (peerinfo->rpc) {
+ peerinfo->rpc = glusterd_rpc_clnt_unref (priv, peerinfo->rpc);
+ peerinfo->rpc = NULL;
+ }
+
+ cds_list_del_rcu (&peerinfo->uuid_list);
+ /* Saving THIS, as it is needed by the callback function */
+ peerinfo->head.this = THIS;
+ call_rcu (&peerinfo->head.head, glusterd_peerinfo_destroy);
+
+ if (quorum_action)
+ glusterd_do_quorum_action ();
+ return 0;
}
/* glusterd_peerinfo_find_by_hostname searches for a peer which matches the
@@ -166,6 +174,7 @@ glusterd_peerinfo_find_by_uuid (uuid_t uuid)
{
glusterd_conf_t *priv = NULL;
glusterd_peerinfo_t *entry = NULL;
+ glusterd_peerinfo_t *found = NULL;
xlator_t *this = NULL;
this = THIS;
@@ -178,19 +187,23 @@ glusterd_peerinfo_find_by_uuid (uuid_t uuid)
if (uuid_is_null (uuid))
return NULL;
- cds_list_for_each_entry (entry, &priv->peers, uuid_list) {
+ rcu_read_lock ();
+ cds_list_for_each_entry_rcu (entry, &priv->peers, uuid_list) {
if (!uuid_compare (entry->uuid, uuid)) {
gf_log (this->name, GF_LOG_DEBUG,
"Friend found... state: %s",
glusterd_friend_sm_state_name_get (entry->state.state));
- return entry;
+ found = entry; /* Probably should be rcu_dereferenced */
+ break;
}
}
+ rcu_read_unlock ();
- gf_log (this->name, GF_LOG_DEBUG, "Friend with uuid: %s, not found",
- uuid_utoa (uuid));
- return NULL;
+ if (!found)
+ gf_log (this->name, GF_LOG_DEBUG,
+ "Friend with uuid: %s, not found", uuid_utoa (uuid));
+ return found;
}
/* glusterd_peerinfo_find will search for a peer matching either @uuid or
@@ -282,6 +295,8 @@ glusterd_peerinfo_new (glusterd_friend_sm_state_t state, uuid_t *uuid,
if (new_peer->state.state == GD_FRIEND_STATE_BEFRIENDED)
new_peer->quorum_contrib = QUORUM_WAITING;
new_peer->port = port;
+
+ pthread_mutex_init (&new_peer->delete_lock, NULL);
out:
if (ret && new_peer) {
glusterd_peerinfo_cleanup (new_peer);
@@ -303,7 +318,8 @@ glusterd_chk_peers_connected_befriended (uuid_t skip_uuid)
priv= THIS->private;
GF_ASSERT (priv);
- cds_list_for_each_entry (peerinfo, &priv->peers, uuid_list) {
+ rcu_read_lock ();
+ cds_list_for_each_entry_rcu (peerinfo, &priv->peers, uuid_list) {
if (!uuid_is_null (skip_uuid) && !uuid_compare (skip_uuid,
peerinfo->uuid))
@@ -315,6 +331,8 @@ glusterd_chk_peers_connected_befriended (uuid_t skip_uuid)
break;
}
}
+ rcu_read_unlock ();
+
gf_log (THIS->name, GF_LOG_DEBUG, "Returning %s",
(ret?"TRUE":"FALSE"));
return ret;
@@ -336,14 +354,16 @@ glusterd_uuid_to_hostname (uuid_t uuid)
if (!uuid_compare (MY_UUID, uuid)) {
hostname = gf_strdup ("localhost");
}
+ rcu_read_lock ();
if (!cds_list_empty (&priv->peers)) {
- cds_list_for_each_entry (entry, &priv->peers, uuid_list) {
+ cds_list_for_each_entry_rcu (entry, &priv->peers, uuid_list) {
if (!uuid_compare (entry->uuid, uuid)) {
hostname = gf_strdup (entry->hostname);
break;
}
}
}
+ rcu_read_unlock ();
return hostname;
}
@@ -373,7 +393,8 @@ glusterd_are_vol_all_peers_up (glusterd_volinfo_t *volinfo,
if (!uuid_compare (brickinfo->uuid, MY_UUID))
continue;
- cds_list_for_each_entry (peerinfo, peers, uuid_list) {
+ rcu_read_lock ();
+ cds_list_for_each_entry_rcu (peerinfo, peers, uuid_list) {
if (uuid_compare (peerinfo->uuid, brickinfo->uuid))
continue;
@@ -385,9 +406,11 @@ glusterd_are_vol_all_peers_up (glusterd_volinfo_t *volinfo,
*down_peerstr = gf_strdup (peerinfo->hostname);
gf_log ("", GF_LOG_DEBUG, "Peer %s is down. ",
peerinfo->hostname);
+ rcu_read_unlock ();
goto out;
}
}
+ rcu_read_unlock ();
}
ret = _gf_true;
@@ -479,7 +502,7 @@ gd_add_address_to_peer (glusterd_peerinfo_t *peerinfo, const char *address)
if (ret)
goto out;
- cds_list_add_tail (&hostname->hostname_list, &peerinfo->hostnames);
+ cds_list_add_tail_rcu (&hostname->hostname_list, &peerinfo->hostnames);
ret = 0;
out:
@@ -584,6 +607,7 @@ gd_peerinfo_find_from_hostname (const char *hoststr)
xlator_t *this = NULL;
glusterd_conf_t *priv = NULL;
glusterd_peerinfo_t *peer = NULL;
+ glusterd_peerinfo_t *found = NULL;
glusterd_peer_hostname_t *tmphost = NULL;
this = THIS;
@@ -593,19 +617,24 @@ gd_peerinfo_find_from_hostname (const char *hoststr)
GF_VALIDATE_OR_GOTO (this->name, (hoststr != NULL), out);
- cds_list_for_each_entry (peer, &priv->peers, uuid_list) {
- cds_list_for_each_entry (tmphost, &peer->hostnames,
- hostname_list) {
+ rcu_read_lock ();
+ cds_list_for_each_entry_rcu (peer, &priv->peers, uuid_list) {
+ cds_list_for_each_entry_rcu (tmphost, &peer->hostnames,
+ hostname_list) {
if (!strncasecmp (tmphost->hostname, hoststr, 1024)) {
gf_log (this->name, GF_LOG_DEBUG,
"Friend %s found.. state: %d",
tmphost->hostname, peer->state.state);
- return peer;
+ found = peer; /* Probably needs to be
+ dereferenced*/
+ goto unlock;
}
}
}
+unlock:
+ rcu_read_unlock ();
out:
- return NULL;
+ return found;
}
/* gd_peerinfo_find_from_addrinfo iterates over all the addresses saved for each
@@ -624,6 +653,7 @@ gd_peerinfo_find_from_addrinfo (const struct addrinfo *addr)
xlator_t *this = NULL;
glusterd_conf_t *conf = NULL;
glusterd_peerinfo_t *peer = NULL;
+ glusterd_peerinfo_t *found = NULL;
glusterd_peer_hostname_t *address = NULL;
int ret = 0;
struct addrinfo *paddr = NULL;
@@ -636,9 +666,10 @@ gd_peerinfo_find_from_addrinfo (const struct addrinfo *addr)
GF_VALIDATE_OR_GOTO (this->name, (addr != NULL), out);
- cds_list_for_each_entry (peer, &conf->peers, uuid_list) {
- cds_list_for_each_entry (address, &peer->hostnames,
- hostname_list) {
+ rcu_read_lock ();
+ cds_list_for_each_entry_rcu (peer, &conf->peers, uuid_list) {
+ cds_list_for_each_entry_rcu (address, &peer->hostnames,
+ hostname_list) {
/* TODO: Cache the resolved addrinfos to improve
* performance
*/
@@ -658,14 +689,20 @@ gd_peerinfo_find_from_addrinfo (const struct addrinfo *addr)
for (tmp = paddr; tmp != NULL; tmp = tmp->ai_next) {
if (gf_compare_sockaddr (addr->ai_addr,
tmp->ai_addr)) {
- freeaddrinfo (paddr);
- return peer;
+ found = peer; /* (de)referenced? */
+ break;
}
}
+
+ freeaddrinfo (paddr);
+ if (found)
+ goto unlock;
}
}
+unlock:
+ rcu_read_unlock ();
out:
- return NULL;
+ return found;
}
/* gd_update_peerinfo_from_dict will update the hostnames for @peerinfo from