/* Copyright (c) 2014 Red Hat, Inc. This file is part of GlusterFS. This file is licensed to you under your choice of the GNU Lesser General Public License, version 3 or any later version (LGPLv3 or later), or the GNU General Public License, version 2 (GPLv2), in all cases as published by the Free Software Foundation. */ #include "glusterd-peer-utils.h" #include "glusterd-store.h" #include "glusterd-server-quorum.h" #include "glusterd-messages.h" #include #include "glusterd-utils.h" void glusterd_peerinfo_destroy(struct rcu_head *head) { int32_t ret = -1; glusterd_peerinfo_t *peerinfo = NULL; glusterd_peer_hostname_t *hostname = NULL; glusterd_peer_hostname_t *tmp = NULL; /* This works as rcu_head is the first member of gd_rcu_head */ peerinfo = caa_container_of((gd_rcu_head *)head, glusterd_peerinfo_t, rcu_head); /* Set THIS to the saved this. Needed by some functions below */ THIS = peerinfo->rcu_head.this; CDS_INIT_LIST_HEAD(&peerinfo->uuid_list); ret = glusterd_store_delete_peerinfo(peerinfo); if (ret) { gf_msg("glusterd", GF_LOG_ERROR, errno, GD_MSG_PEERINFO_DELETE_FAIL, "Deleting peer info failed"); } GF_FREE(peerinfo->hostname); peerinfo->hostname = NULL; cds_list_for_each_entry_safe(hostname, tmp, &peerinfo->hostnames, hostname_list) { glusterd_peer_hostname_free(hostname); } glusterd_sm_tr_log_delete(&peerinfo->sm_log); pthread_mutex_unlock(&peerinfo->delete_lock); pthread_mutex_destroy(&peerinfo->delete_lock); GF_FREE(peerinfo); peerinfo = NULL; return; } int32_t glusterd_peerinfo_cleanup(glusterd_peerinfo_t *peerinfo) { GF_ASSERT(peerinfo); 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; } 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->rcu_head.this = THIS; call_rcu(&peerinfo->rcu_head.head, glusterd_peerinfo_destroy); if (quorum_action) /* coverity[SLEEP] */ glusterd_do_quorum_action(); return 0; } /* gd_peerinfo_find_from_hostname iterates over all the addresses saved for each * peer and matches it to @hoststr. * Returns the matched peer if found else returns NULL */ static glusterd_peerinfo_t * gd_peerinfo_find_from_hostname(const char *hoststr) { xlator_t *this = THIS; glusterd_conf_t *priv = NULL; glusterd_peerinfo_t *peer = NULL; glusterd_peerinfo_t *found = NULL; glusterd_peer_hostname_t *tmphost = NULL; GF_ASSERT(this != NULL); priv = this->private; GF_VALIDATE_OR_GOTO(this->name, (priv != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (hoststr != NULL), out); 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_msg_debug(this->name, 0, "Friend %s found.. state: %d", tmphost->hostname, peer->state.state); found = peer; /* Probably needs to be dereferenced*/ goto unlock; } } } unlock: RCU_READ_UNLOCK; out: return found; } /* gd_peerinfo_find_from_addrinfo iterates over all the addresses saved for each * peer, resolves them and compares them to @addr. * * * NOTE: As getaddrinfo is a blocking call and is being performed multiple times * in this function, it could lead to the calling thread to be blocked for * significant amounts of time. * * Returns the matched peer if found else returns NULL */ static glusterd_peerinfo_t * gd_peerinfo_find_from_addrinfo(const struct addrinfo *addr) { xlator_t *this = THIS; 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; struct addrinfo *tmp = NULL; GF_ASSERT(this != NULL); conf = this->private; GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); 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 */ ret = getaddrinfo(address->hostname, NULL, NULL, &paddr); if (ret) { /* Don't fail if getaddrinfo fails, continue * onto the next address */ gf_msg_trace(this->name, 0, "getaddrinfo for %s failed (%s)", address->hostname, gai_strerror(ret)); continue; } for (tmp = paddr; tmp != NULL; tmp = tmp->ai_next) { if (gf_compare_sockaddr(addr->ai_addr, tmp->ai_addr)) { found = peer; /* (de)referenced? */ break; } } freeaddrinfo(paddr); if (found) goto unlock; } } unlock: RCU_READ_UNLOCK; out: return found; } /* glusterd_peerinfo_find_by_hostname searches for a peer which matches the * hostname @hoststr and if found returns the pointer to peerinfo object. * Returns NULL otherwise. * * It first attempts a quick search by string matching @hoststr. If that fails, * it'll attempt a more thorough match by resolving the addresses and matching * the resolved addrinfos. */ glusterd_peerinfo_t * glusterd_peerinfo_find_by_hostname(const char *hoststr) { int ret = -1; struct addrinfo *addr = NULL; struct addrinfo *p = NULL; xlator_t *this = THIS; glusterd_peerinfo_t *peerinfo = NULL; GF_ASSERT(hoststr); peerinfo = gd_peerinfo_find_from_hostname(hoststr); if (peerinfo) return peerinfo; ret = getaddrinfo(hoststr, NULL, NULL, &addr); if (ret != 0) { gf_msg(this->name, GF_LOG_ERROR, ret, GD_MSG_GETADDRINFO_FAIL, "error in getaddrinfo: %s\n", gai_strerror(ret)); goto out; } for (p = addr; p != NULL; p = p->ai_next) { peerinfo = gd_peerinfo_find_from_addrinfo(p); if (peerinfo) { freeaddrinfo(addr); return peerinfo; } } out: gf_msg_debug(this->name, 0, "Unable to find friend: %s", hoststr); if (addr) freeaddrinfo(addr); return NULL; } int glusterd_hostname_to_uuid(char *hostname, uuid_t uuid) { GF_ASSERT(hostname); GF_ASSERT(uuid); glusterd_peerinfo_t *peerinfo = NULL; glusterd_conf_t *priv = NULL; int ret = -1; xlator_t *this = NULL; this = THIS; GF_ASSERT(this); priv = this->private; GF_ASSERT(priv); peerinfo = glusterd_peerinfo_find_by_hostname(hostname); if (peerinfo) { ret = 0; gf_uuid_copy(uuid, peerinfo->uuid); } else { if (gf_is_local_addr(hostname)) { gf_uuid_copy(uuid, MY_UUID); ret = 0; } else { ret = -1; } } gf_msg_debug(this->name, 0, "returning %d", ret); return ret; } /* glusterd_peerinfo_find_by_uuid searches for a peer which matches the * uuid @uuid and if found returns the pointer to peerinfo object. * Returns NULL otherwise. */ glusterd_peerinfo_t * 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 = THIS; glusterd_friend_sm_state_t state; GF_ASSERT(this); if (gf_uuid_is_null(uuid)) return NULL; priv = this->private; GF_ASSERT(priv); RCU_READ_LOCK; cds_list_for_each_entry_rcu(entry, &priv->peers, uuid_list) { if (!gf_uuid_compare(entry->uuid, uuid)) { found = entry; /* Probably should be rcu_dereferenced */ state = found->state.state; break; } } RCU_READ_UNLOCK; if (found) gf_msg_debug(this->name, 0, "Friend found... state: %s", glusterd_friend_sm_state_name_get(state)); else gf_msg_debug(this->name, 0, "Friend with uuid: %s, not found", uuid_utoa(uuid)); return found; } /* glusterd_peerinfo_find will search for a peer matching either @uuid or * @hostname and return a pointer to the peerinfo object * Returns NULL otherwise. */ glusterd_peerinfo_t * glusterd_peerinfo_find(uuid_t uuid, const char *hostname) { glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = THIS; GF_ASSERT(this); if (uuid) { peerinfo = glusterd_peerinfo_find_by_uuid(uuid); if (peerinfo) { return peerinfo; } else { gf_msg_debug(this->name, 0, "Unable to find peer by uuid: %s", uuid_utoa(uuid)); } } if (hostname) { peerinfo = glusterd_peerinfo_find_by_hostname(hostname); if (peerinfo) { return peerinfo; } else { gf_msg_debug(this->name, 0, "Unable to find hostname: %s", hostname); } } return NULL; } /* glusterd_peerinfo_new will create a new peerinfo object and set it's members * values using the passed parameters. * @hostname is added as the first entry in peerinfo->hostnames list and also * set to peerinfo->hostname. * It returns a pointer to peerinfo object if successful and returns NULL * otherwise. The caller should take care of freeing the created peerinfo * object. */ glusterd_peerinfo_t * glusterd_peerinfo_new(glusterd_friend_sm_state_t state, uuid_t *uuid, const char *hostname, int port) { glusterd_peerinfo_t *new_peer = NULL; int ret = -1; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; this = THIS; GF_ASSERT(this); conf = this->private; GF_ASSERT(conf); new_peer = GF_CALLOC(1, sizeof(*new_peer), gf_gld_mt_peerinfo_t); if (!new_peer) goto out; CDS_INIT_LIST_HEAD(&new_peer->uuid_list); new_peer->state.state = state; CDS_INIT_LIST_HEAD(&new_peer->hostnames); if (hostname) { ret = gd_add_address_to_peer(new_peer, hostname); if (ret) goto out; /* Also set it to peerinfo->hostname. Doing this as we use * peerinfo->hostname in a lot of places and is really hard to * get everything right */ new_peer->hostname = gf_strdup(hostname); } if (uuid) { gf_uuid_copy(new_peer->uuid, *uuid); } ret = glusterd_sm_tr_log_init( &new_peer->sm_log, glusterd_friend_sm_state_name_get, glusterd_friend_sm_event_name_get, GLUSTERD_TR_LOG_SIZE); if (ret) goto out; 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); new_peer->generation = uatomic_add_return(&conf->generation, 1); out: if (ret && new_peer) { glusterd_peerinfo_cleanup(new_peer); new_peer = NULL; } return new_peer; } /* Check if the all peers are connected and befriended, except the peer * specified (the peer being detached) */ gf_boolean_t glusterd_chk_peers_connected_befriended(uuid_t skip_uuid) { gf_boolean_t ret = _gf_true; glusterd_peerinfo_t *peerinfo = NULL; glusterd_conf_t *priv = NULL; priv = THIS->private; GF_ASSERT(priv); RCU_READ_LOCK; cds_list_for_each_entry_rcu(peerinfo, &priv->peers, uuid_list) { if (!gf_uuid_is_null(skip_uuid) && !gf_uuid_compare(skip_uuid, peerinfo->uuid)) continue; if ((GD_FRIEND_STATE_BEFRIENDED != peerinfo->state.state) || !(peerinfo->connected)) { ret = _gf_false; break; } } RCU_READ_UNLOCK; gf_msg_debug(THIS->name, 0, "Returning %s", (ret ? "TRUE" : "FALSE")); return ret; } /* Return hostname for given uuid if it exists * else return NULL */ char * glusterd_uuid_to_hostname(uuid_t uuid) { char *hostname = NULL; glusterd_conf_t *priv = NULL; glusterd_peerinfo_t *entry = NULL; priv = THIS->private; GF_ASSERT(priv); if (!gf_uuid_compare(MY_UUID, uuid)) { hostname = gf_strdup("localhost"); return hostname; } RCU_READ_LOCK; if (!cds_list_empty(&priv->peers)) { cds_list_for_each_entry_rcu(entry, &priv->peers, uuid_list) { if (!gf_uuid_compare(entry->uuid, uuid)) { hostname = gf_strdup(entry->hostname); break; } } } RCU_READ_UNLOCK; return hostname; } char * gd_peer_uuid_str(glusterd_peerinfo_t *peerinfo) { if ((peerinfo == NULL) || gf_uuid_is_null(peerinfo->uuid)) return NULL; if (peerinfo->uuid_str[0] == '\0') uuid_utoa_r(peerinfo->uuid, peerinfo->uuid_str); return peerinfo->uuid_str; } gf_boolean_t glusterd_are_all_peers_up() { glusterd_peerinfo_t *peerinfo = NULL; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; gf_boolean_t peers_up = _gf_false; this = THIS; GF_VALIDATE_OR_GOTO("glusterd", this, out); conf = this->private; GF_VALIDATE_OR_GOTO(this->name, conf, out); RCU_READ_LOCK; cds_list_for_each_entry_rcu(peerinfo, &conf->peers, uuid_list) { if (!peerinfo->connected) { RCU_READ_UNLOCK; goto out; } } RCU_READ_UNLOCK; peers_up = _gf_true; out: return peers_up; } gf_boolean_t glusterd_are_vol_all_peers_up(glusterd_volinfo_t *volinfo, struct cds_list_head *peers, char **down_peerstr) { glusterd_peerinfo_t *peerinfo = NULL; glusterd_brickinfo_t *brickinfo = NULL; gf_boolean_t ret = _gf_false; cds_list_for_each_entry(brickinfo, &volinfo->bricks, brick_list) { if (!gf_uuid_compare(brickinfo->uuid, MY_UUID)) continue; RCU_READ_LOCK; cds_list_for_each_entry_rcu(peerinfo, peers, uuid_list) { if (gf_uuid_compare(peerinfo->uuid, brickinfo->uuid)) continue; /*Found peer who owns the brick, return false * if peer is not connected or not friend */ if (!(peerinfo->connected) || (peerinfo->state.state != GD_FRIEND_STATE_BEFRIENDED)) { *down_peerstr = gf_strdup(peerinfo->hostname); RCU_READ_UNLOCK; gf_msg_debug(THIS->name, 0, "Peer %s is down. ", *down_peerstr); goto out; } } RCU_READ_UNLOCK; } ret = _gf_true; out: gf_msg_debug("glusterd", 0, "Returning %d", ret); return ret; } int32_t glusterd_peer_hostname_new(const char *hostname, glusterd_peer_hostname_t **name) { glusterd_peer_hostname_t *peer_hostname = NULL; int32_t ret = -1; GF_ASSERT(hostname); GF_ASSERT(name); peer_hostname = GF_CALLOC(1, sizeof(*peer_hostname), gf_gld_mt_peer_hostname_t); if (!peer_hostname) goto out; peer_hostname->hostname = gf_strdup(hostname); CDS_INIT_LIST_HEAD(&peer_hostname->hostname_list); *name = peer_hostname; ret = 0; out: gf_msg_debug("glusterd", 0, "Returning %d", ret); return ret; } void glusterd_peer_hostname_free(glusterd_peer_hostname_t *name) { if (!name) return; cds_list_del_init(&name->hostname_list); GF_FREE(name->hostname); name->hostname = NULL; GF_FREE(name); return; } gf_boolean_t gd_peer_has_address(glusterd_peerinfo_t *peerinfo, const char *address) { glusterd_peer_hostname_t *hostname = NULL; GF_VALIDATE_OR_GOTO("glusterd", (peerinfo != NULL), out); GF_VALIDATE_OR_GOTO("glusterd", (address != NULL), out); cds_list_for_each_entry(hostname, &peerinfo->hostnames, hostname_list) { if (strcmp(hostname->hostname, address) == 0) { return _gf_true; } } out: return _gf_false; } int gd_add_address_to_peer(glusterd_peerinfo_t *peerinfo, const char *address) { int ret = -1; glusterd_peer_hostname_t *hostname = NULL; GF_VALIDATE_OR_GOTO("glusterd", (peerinfo != NULL), out); GF_VALIDATE_OR_GOTO("glusterd", (address != NULL), out); if (gd_peer_has_address(peerinfo, address)) { ret = 0; goto out; } ret = glusterd_peer_hostname_new(address, &hostname); if (ret) goto out; cds_list_add_tail_rcu(&hostname->hostname_list, &peerinfo->hostnames); ret = 0; out: return ret; } /* gd_add_friend_to_dict() adds details of @friend into @dict with the given * @prefix. All the parameters are compulsory. * * The complete address list is added to the dict only if the cluster op-version * is >= GD_OP_VERSION_3_6_0 */ int gd_add_friend_to_dict(glusterd_peerinfo_t *friend, dict_t *dict, const char *prefix) { int ret = -1; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; char key[100] = { 0, }; glusterd_peer_hostname_t *address = NULL; int count = 0; this = THIS; GF_VALIDATE_OR_GOTO("glusterd", (this != NULL), out); conf = this->private; GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (friend != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (dict != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (prefix != NULL), out); snprintf(key, sizeof(key), "%s.uuid", prefix); ret = dict_set_dynstr_with_alloc(dict, key, uuid_utoa(friend->uuid)); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "Failed to set key %s in dict", key); goto out; } /* Setting the first hostname from the list with this key for backward * compatibility */ snprintf(key, sizeof(key), "%s.hostname", prefix); address = cds_list_entry(&friend->hostnames, glusterd_peer_hostname_t, hostname_list); ret = dict_set_dynstr_with_alloc(dict, key, address->hostname); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "Failed to set key %s in dict", key); goto out; } if (conf->op_version < GD_OP_VERSION_3_6_0) { ret = 0; goto out; } address = NULL; count = 0; cds_list_for_each_entry(address, &friend->hostnames, hostname_list) { GF_VALIDATE_OR_GOTO(this->name, (address != NULL), out); snprintf(key, sizeof(key), "%s.hostname%d", prefix, count); ret = dict_set_dynstr_with_alloc(dict, key, address->hostname); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "Failed to set key %s in dict", key); goto out; } count++; } ret = snprintf(key, sizeof(key), "%s.address-count", prefix); ret = dict_set_int32n(dict, key, ret, count); if (ret) gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED, "Failed to set key %s in dict", key); out: gf_msg_debug(this ? this->name : "glusterd", 0, "Returning %d", ret); return ret; } /* gd_update_peerinfo_from_dict will update the hostnames for @peerinfo from * peer details with @prefix in @dict. * Returns 0 on success and -1 on failure. */ int gd_update_peerinfo_from_dict(glusterd_peerinfo_t *peerinfo, dict_t *dict, const char *prefix) { int ret = -1; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; char key[100] = { 0, }; char *hostname = NULL; int count = 0; int i = 0; this = THIS; GF_ASSERT(this != NULL); conf = this->private; GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (peerinfo != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (dict != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (prefix != NULL), out); ret = snprintf(key, sizeof(key), "%s.hostname", prefix); ret = dict_get_strn(dict, key, ret, &hostname); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "Key %s not present in " "dictionary", key); goto out; } ret = gd_add_address_to_peer(peerinfo, hostname); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_ADD_ADDRESS_TO_PEER_FAIL, "Could not add address to peer"); goto out; } /* Also set peerinfo->hostname to the first address */ if (peerinfo->hostname != NULL) GF_FREE(peerinfo->hostname); peerinfo->hostname = gf_strdup(hostname); if (conf->op_version < GD_OP_VERSION_3_6_0) { ret = 0; goto out; } ret = snprintf(key, sizeof(key), "%s.address-count", prefix); ret = dict_get_int32n(dict, key, ret, &count); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "Key %s not present in " "dictionary", key); goto out; } hostname = NULL; for (i = 0; i < count; i++) { ret = snprintf(key, sizeof(key), "%s.hostname%d", prefix, i); ret = dict_get_strn(dict, key, ret, &hostname); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "Key %s not present " "in dictionary", key); goto out; } ret = gd_add_address_to_peer(peerinfo, hostname); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_ADD_ADDRESS_TO_PEER_FAIL, "Could not add address to peer"); goto out; } hostname = NULL; } out: gf_msg_debug(this->name, 0, "Returning %d", ret); return ret; } /* gd_peerinfo_from_dict creates a peerinfo object from details of peer with * @prefix in @dict. * Returns a pointer to the created peerinfo object on success, and NULL on * failure. */ glusterd_peerinfo_t * gd_peerinfo_from_dict(dict_t *dict, const char *prefix) { int ret = -1; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; glusterd_peerinfo_t *new_peer = NULL; char key[64] = { 0, }; char *uuid_str = NULL; this = THIS; GF_VALIDATE_OR_GOTO("glusterd", (this != NULL), out); conf = this->private; GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (dict != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (prefix != NULL), out); new_peer = glusterd_peerinfo_new(GD_FRIEND_STATE_DEFAULT, NULL, NULL, 0); if (new_peer == NULL) { ret = -1; gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_PEERINFO_CREATE_FAIL, "Could not create peerinfo " "object"); goto out; } ret = snprintf(key, sizeof(key), "%s.uuid", prefix); ret = dict_get_strn(dict, key, ret, &uuid_str); if (ret) { gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_GET_FAILED, "Key %s not present in " "dictionary", key); goto out; } gf_uuid_parse(uuid_str, new_peer->uuid); ret = gd_update_peerinfo_from_dict(new_peer, dict, prefix); out: if ((ret != 0) && (new_peer != NULL)) { glusterd_peerinfo_cleanup(new_peer); new_peer = NULL; } return new_peer; } static int gd_add_peer_hostnames_to_dict(glusterd_peerinfo_t *peerinfo, dict_t *dict, const char *prefix) { int ret = -1; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; char key[64] = { 0, }; glusterd_peer_hostname_t *addr = NULL; int count = 0; this = THIS; GF_ASSERT(this != NULL); conf = this->private; GF_VALIDATE_OR_GOTO(this->name, (conf != NULL), out); if (conf->op_version < GD_OP_VERSION_3_6_0) { ret = 0; goto out; } GF_VALIDATE_OR_GOTO(this->name, (peerinfo != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (dict != NULL), out); GF_VALIDATE_OR_GOTO(this->name, (prefix != NULL), out); cds_list_for_each_entry(addr, &peerinfo->hostnames, hostname_list) { snprintf(key, sizeof(key), "%s.hostname%d", prefix, count); ret = dict_set_dynstr_with_alloc(dict, key, addr->hostname); if (ret) goto out; count++; } ret = snprintf(key, sizeof(key), "%s.hostname_count", prefix); ret = dict_set_int32n(dict, key, ret, count); out: return ret; } int gd_add_peer_detail_to_dict(glusterd_peerinfo_t *peerinfo, dict_t *friends, int count) { int ret = -1; char key[32] = { 0, }; int keylen; char *peer_uuid_str = NULL; GF_ASSERT(peerinfo); GF_ASSERT(friends); peer_uuid_str = gd_peer_uuid_str(peerinfo); keylen = snprintf(key, sizeof(key), "friend%d.uuid", count); ret = dict_set_strn(friends, key, keylen, peer_uuid_str); if (ret) goto out; keylen = snprintf(key, sizeof(key), "friend%d.hostname", count); ret = dict_set_strn(friends, key, keylen, peerinfo->hostname); if (ret) goto out; keylen = snprintf(key, sizeof(key), "friend%d.port", count); ret = dict_set_int32n(friends, key, keylen, peerinfo->port); if (ret) goto out; keylen = snprintf(key, sizeof(key), "friend%d.stateId", count); ret = dict_set_int32n(friends, key, keylen, peerinfo->state.state); if (ret) goto out; keylen = snprintf(key, sizeof(key), "friend%d.state", count); ret = dict_set_strn( friends, key, keylen, glusterd_friend_sm_state_name_get(peerinfo->state.state)); if (ret) goto out; keylen = snprintf(key, sizeof(key), "friend%d.connected", count); ret = dict_set_int32n(friends, key, keylen, (int32_t)peerinfo->connected); if (ret) goto out; snprintf(key, sizeof(key), "friend%d", count); ret = gd_add_peer_hostnames_to_dict(peerinfo, friends, key); out: return ret; } /* glusterd_peerinfo_find_by_generation searches for a peer which has the * generation number @generation and if found returns the pointer to peerinfo * object. Returns NULL otherwise. */ glusterd_peerinfo_t * glusterd_peerinfo_find_by_generation(uint32_t generation) { glusterd_conf_t *priv = NULL; glusterd_peerinfo_t *entry = NULL; glusterd_peerinfo_t *found = NULL; xlator_t *this = THIS; glusterd_friend_sm_state_t state; GF_ASSERT(this); priv = this->private; GF_ASSERT(priv); RCU_READ_LOCK; cds_list_for_each_entry_rcu(entry, &priv->peers, uuid_list) { if (entry->generation == generation) { found = entry; /* Probably should be rcu_dereferenced */ state = found->state.state; break; } } RCU_READ_UNLOCK; if (found) gf_msg_debug(this->name, 0, "Friend found... state: %s", glusterd_friend_sm_state_name_get(state)); else gf_msg_debug(this->name, 0, "Friend with generation: %" PRIu32 ", not found", generation); return found; } int glusterd_get_peers_count() { int count = 0; xlator_t *this = NULL; glusterd_conf_t *conf = NULL; glusterd_peerinfo_t *peer = NULL; this = THIS; GF_VALIDATE_OR_GOTO("glusterd", this, out); conf = this->private; GF_VALIDATE_OR_GOTO(this->name, conf, out); RCU_READ_LOCK; cds_list_for_each_entry_rcu(peer, &conf->peers, uuid_list) count++; RCU_READ_UNLOCK; out: return count; }