Beispiel #1
0
/*******************************************************************************
 * FI_AV_TABLE specific implementations.
 ******************************************************************************/
static int table_insert(struct gnix_fid_av *av_priv, const void *addr,
			size_t count, fi_addr_t *fi_addr, uint64_t flags,
			void *context)
{
	struct gnix_ep_name ep_name;
	int ret = count;
	size_t index, i;
	int *entry_err = context;

	if (gnix_check_capacity(av_priv, count)) {
		return -FI_ENOMEM;
	}

	assert(av_priv->table);

	for (index = av_priv->count, i = 0; i < count; index++, i++) {
		_gnix_get_ep_name(addr, i, &ep_name, av_priv->domain);

		/* check if this ep_name fits in the av context bits */
		if (ep_name.name_type & GNIX_EPN_TYPE_SEP) {
			if ((1 << av_priv->rx_ctx_bits) < ep_name.rx_ctx_cnt) {
				if (flags & FI_SYNC_ERR) {
					entry_err[i] = -FI_EINVAL;
					fi_addr[i] = FI_ADDR_NOTAVAIL;
					ret = -FI_EINVAL;
					continue;
				}
				GNIX_DEBUG(FI_LOG_AV, "ep_name doesn't fit "
					"into the av context bits\n");
				return -FI_EINVAL;
			}
		}

		av_priv->table[index].gnix_addr = ep_name.gnix_addr;
		av_priv->valid_entry_vec[index] = 1;
		av_priv->table[index].name_type = ep_name.name_type;
		av_priv->table[index].cookie = ep_name.cookie;
		av_priv->table[index].rx_ctx_cnt = ep_name.rx_ctx_cnt;
		av_priv->table[index].cm_nic_cdm_id =
			ep_name.cm_nic_cdm_id;
		av_priv->table[index].key_offset = ep_name.key_offset;
		if (fi_addr)
			fi_addr[i] = index;

		if (flags & FI_SYNC_ERR) {
			entry_err[i] = FI_SUCCESS;
		}
	}

	av_priv->count += count;

	return ret;
}
Beispiel #2
0
static int map_insert(struct gnix_fid_av *av_priv, const void *addr,
		      size_t count, fi_addr_t *fi_addr, uint64_t flags,
		      void *context)
{
	int ret;
	struct gnix_ep_name ep_name;
	struct gnix_av_addr_entry *the_entry;
	gnix_ht_key_t key;
	size_t i;
	struct gnix_av_block *blk = NULL;
	int ret_cnt = count;
	int *entry_err = context;

	assert(av_priv->map_ht != NULL);

	if (count == 0)
		return 0;

	blk = calloc(1, sizeof(struct gnix_av_block));
	if (blk == NULL)
		return -FI_ENOMEM;

	blk->base =  calloc(count, sizeof(struct gnix_av_addr_entry));
	if (blk->base == NULL) {
		free(blk);
		return -FI_ENOMEM;
	}

	slist_insert_tail(&blk->slist, &av_priv->block_list);

	for (i = 0; i < count; i++) {
		_gnix_get_ep_name(addr, i, &ep_name, av_priv->domain);

		/* check if this ep_name fits in the av context bits */
		if (ep_name.name_type & GNIX_EPN_TYPE_SEP) {
			if ((1 << av_priv->rx_ctx_bits) < ep_name.rx_ctx_cnt) {
				if (flags & FI_SYNC_ERR) {
					entry_err[i] = -FI_EINVAL;
					fi_addr[i] = FI_ADDR_NOTAVAIL;
					ret_cnt = -FI_EINVAL;
					continue;
				}
				GNIX_DEBUG(FI_LOG_DEBUG, "ep_name doesn't fit "
					"into the av context bits\n");
				return -FI_EINVAL;
			}
		}

		((struct gnix_address *)fi_addr)[i] = ep_name.gnix_addr;
		the_entry =  &blk->base[i];
		memcpy(&the_entry->gnix_addr, &ep_name.gnix_addr,
		       sizeof(struct gnix_address));
		the_entry->name_type = ep_name.name_type;
		the_entry->cm_nic_cdm_id = ep_name.cm_nic_cdm_id;
		the_entry->cookie = ep_name.cookie;
		the_entry->rx_ctx_cnt = ep_name.rx_ctx_cnt;
		memcpy(&key, &ep_name.gnix_addr, sizeof(gnix_ht_key_t));
		ret = _gnix_ht_insert(av_priv->map_ht,
				      key,
				      the_entry);

		if (flags & FI_SYNC_ERR) {
			entry_err[i] = FI_SUCCESS;
		}

		/*
		 * we are okay with user trying to add more
		 * entries with same key.
		 */
		if ((ret != FI_SUCCESS) && (ret != -FI_ENOSPC)) {
			GNIX_WARN(FI_LOG_AV,
				  "_gnix_ht_insert failed %d\n",
				  ret);
			if (flags & FI_SYNC_ERR) {
				entry_err[i] = ret;
				fi_addr[i] = FI_ADDR_NOTAVAIL;
				ret_cnt = ret;
				continue;
			}
			return ret;
		}
	}

	return ret_cnt;
}
Beispiel #3
0
int _gnix_cm_nic_alloc(struct gnix_fid_domain *domain,
		       struct fi_info *info,
		       uint32_t cdm_id,
			   struct gnix_auth_key *auth_key,
		       struct gnix_cm_nic **cm_nic_ptr)
{
	int ret = FI_SUCCESS;
	struct gnix_cm_nic *cm_nic = NULL;
	gnix_hashtable_attr_t gnix_ht_attr = {0};
	uint32_t name_type = GNIX_EPN_TYPE_UNBOUND;
	struct gnix_nic_attr nic_attr = {0};
	struct gnix_ep_name ep_name;
	struct gnix_dgram_hndl_attr dgram_hndl_attr = {0};
	struct gnix_dgram_hndl_attr *dgram_hndl_attr_ptr = NULL;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	*cm_nic_ptr = NULL;

	/*
	 * if app has specified a src_addr in the info
	 * argument and length matches that for gnix_ep_name
	 * we must allocate a cm_nic, otherwise we first
	 * check to see if there is a cm_nic already for this domain
	 * and just use it.
	 */

	if (info->src_addr) {
		/*TODO (optimization): strchr to name_type and strtol */
		_gnix_get_ep_name(info->src_addr, 0, &ep_name, domain);
		name_type = ep_name.name_type;
	}

	GNIX_INFO(FI_LOG_EP_CTRL, "creating cm_nic for %u/0x%x/%u\n",
			auth_key->ptag, auth_key->cookie, cdm_id);

	cm_nic = (struct gnix_cm_nic *)calloc(1, sizeof(*cm_nic));
	if (cm_nic == NULL) {
		ret = -FI_ENOMEM;
		goto err;
	}

	/*
	 * we have to force allocation of a new nic since we want
	 * an a particulard cdm id
	 */
	nic_attr.must_alloc = true;
	nic_attr.use_cdm_id = true;
	nic_attr.cdm_id = cdm_id;
	nic_attr.auth_key = auth_key;

	ret = gnix_nic_alloc(domain, &nic_attr, &cm_nic->nic);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "gnix_nic_alloc returned %s\n",
			  fi_strerror(-ret));
		goto err;
	}

	cm_nic->my_name.gnix_addr.cdm_id = cdm_id;
	cm_nic->ptag = auth_key->ptag;
	cm_nic->my_name.cookie = auth_key->cookie;
	cm_nic->my_name.gnix_addr.device_addr = cm_nic->nic->device_addr;
	cm_nic->domain = domain;
	cm_nic->ctrl_progress = domain->control_progress;
	cm_nic->my_name.name_type = name_type;
	cm_nic->poll_cnt = 0;
	fastlock_init(&cm_nic->wq_lock);
	dlist_init(&cm_nic->cm_nic_wq);

	/*
	 * prep the cm nic's dgram component
	 */
	if (domain->control_progress == FI_PROGRESS_AUTO) {
		dgram_hndl_attr.timeout_needed = __gnix_cm_nic_timeout_needed;
		dgram_hndl_attr.timeout_progress = __gnix_cm_nic_timeout_progress;
		dgram_hndl_attr.timeout_data = (void *)cm_nic;
		dgram_hndl_attr.timeout = domain->params.dgram_progress_timeout;
		dgram_hndl_attr_ptr = &dgram_hndl_attr;
	};

	ret = _gnix_dgram_hndl_alloc(cm_nic,
				     domain->control_progress,
				     dgram_hndl_attr_ptr,
				     &cm_nic->dgram_hndl);
	if (ret != FI_SUCCESS)
		goto err;

	/*
	 * allocate hash table for translating ep addresses
	 * to ep's.
	 * This table will not be large - how many FI_EP_RDM ep's
	 * will an app create using one domain?, nor in the critical path
	 * so just use defaults.
	 */
	cm_nic->addr_to_ep_ht = calloc(1, sizeof(struct gnix_hashtable));
	if (cm_nic->addr_to_ep_ht == NULL)
		goto err;

	gnix_ht_attr.ht_initial_size = 64;
	gnix_ht_attr.ht_maximum_size = 1024;
	gnix_ht_attr.ht_increase_step = 2;
	gnix_ht_attr.ht_increase_type = GNIX_HT_INCREASE_MULT;
	gnix_ht_attr.ht_collision_thresh = 500;
	gnix_ht_attr.ht_hash_seed = 0xdeadbeefbeefdead;
	gnix_ht_attr.ht_internal_locking = 1;
	gnix_ht_attr.destructor = NULL;

	ret = _gnix_ht_init(cm_nic->addr_to_ep_ht, &gnix_ht_attr);
	if (ret != FI_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "gnix_ht_init returned %s\n",
			  fi_strerror(-ret));
		goto err;
	}

	_gnix_ref_init(&cm_nic->ref_cnt, 1, __cm_nic_destruct);

	*cm_nic_ptr = cm_nic;

	pthread_mutex_lock(&gnix_cm_nic_list_lock);
	dlist_insert_tail(&cm_nic->cm_nic_list, &gnix_cm_nic_list);
	pthread_mutex_unlock(&gnix_cm_nic_list_lock);

	return ret;

err:
	if (cm_nic->dgram_hndl)
		_gnix_dgram_hndl_free(cm_nic->dgram_hndl);

	if (cm_nic->nic)
		_gnix_nic_free(cm_nic->nic);

	if (cm_nic->addr_to_ep_ht) {
		_gnix_ht_destroy(cm_nic->addr_to_ep_ht);
		free(cm_nic->addr_to_ep_ht);
	}

	if (cm_nic != NULL)
		free(cm_nic);

	return ret;
}