/* * Copyright (c) 2015-2017 Cray Inc. All rights reserved. * Copyright (c) 2015-2017 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2019 Triad National Security, LLC. * All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // // Address vector common code // #include #include #include #include "gnix.h" #include "gnix_util.h" #include "gnix_hashtable.h" #include "gnix_av.h" #include "gnix_cm.h" /* * local variables and structs */ #define GNIX_AV_ENTRY_VALID (1ULL) #define GNIX_AV_ENTRY_CM_NIC_ID (1ULL << 2) struct gnix_av_block { struct slist_entry slist; struct gnix_av_addr_entry *base; }; /******************************************************************************* * Forward declarations of ops structures. ******************************************************************************/ static struct fi_ops_av gnix_av_ops; static struct fi_ops gnix_fi_av_ops; /******************************************************************************* * Helper functions. ******************************************************************************/ static int gnix_verify_av_attr(struct fi_av_attr *attr) { int ret = FI_SUCCESS; if (attr->rx_ctx_bits > GNIX_RX_CTX_MAX_BITS) { GNIX_WARN(FI_LOG_AV, "rx_ctx_bits too big\n"); return -FI_EINVAL; } switch (attr->type) { case FI_AV_TABLE: case FI_AV_MAP: case FI_AV_UNSPEC: break; default: ret = -FI_EINVAL; break; } if (attr->name != NULL) { ret = -FI_ENOSYS; } return ret; } /* * Check the capacity of the internal table used to represent FI_AV_TABLE type * address vectors. Initially the table starts with a capacity and count of 0 * and the capacity increases by roughly double each time a resize is necessary. */ static int gnix_check_capacity(struct gnix_fid_av *av, size_t count) { struct gnix_av_addr_entry *addrs = NULL; int *valid_entry_vec = NULL; size_t capacity = av->capacity; size_t prev_capacity; /* * av->count + count is the amount of used indices after adding the * count items. */ prev_capacity = capacity; while (capacity < av->count + count) { /* * Handle initial capacity of 0, by adding 1. */ capacity = capacity * 2 + 1; } /* * Don't need to grow the table. */ if (capacity == av->capacity) { return FI_SUCCESS; } addrs = realloc(av->table, capacity * sizeof(*addrs)); if (!addrs) { return -FI_ENOMEM; } memset(&addrs[prev_capacity], 0, (capacity - prev_capacity) * sizeof(*addrs)); valid_entry_vec = realloc(av->valid_entry_vec, capacity * sizeof(int)); if (!valid_entry_vec) { return -FI_ENOMEM; } memset(&valid_entry_vec[prev_capacity], 0, (capacity - prev_capacity) * sizeof(int)); /* * Update table and capacity to reflect new values. */ av->table = addrs; av->valid_entry_vec = valid_entry_vec; av->capacity = capacity; return FI_SUCCESS; } /******************************************************************************* * 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 = FI_SUCCESS, success_cnt = 0; 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++) { ret = _gnix_get_ep_name(addr, i, &ep_name, av_priv->domain); /* check if this ep_name fits in the av context bits */ if ((ret == FI_SUCCESS) && (ep_name.name_type & GNIX_EPN_TYPE_SEP)) { if ((1 << av_priv->rx_ctx_bits) < ep_name.rx_ctx_cnt) { fprintf(stderr, "rx_ctx_bits %d ep.name.rx_ctx_cnt = %d\n", (1 << av_priv->rx_ctx_bits), ep_name.rx_ctx_cnt); ret = -FI_EINVAL; GNIX_DEBUG(FI_LOG_AV, "ep_name doesn't fit " "into the av context bits\n"); } } if (ret != FI_SUCCESS) { if (flags & FI_SYNC_ERR) { entry_err[i] = ret; if (fi_addr) fi_addr[i] = FI_ADDR_NOTAVAIL; continue; } else { return -FI_EINVAL; } } else { if (flags & FI_SYNC_ERR) entry_err[i] = FI_SUCCESS; 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; success_cnt++; } } av_priv->count += success_cnt; ret = success_cnt; return ret; } /* * Currently only marks as 'not valid'. Should actually free memory. * If any of the given address fail to be removed (are already marked removed) * then the return value will be -FI_EINVAL. */ static int table_remove(struct gnix_fid_av *av_priv, fi_addr_t *fi_addr, size_t count, uint64_t flags) { int ret = FI_SUCCESS; size_t index; size_t i; for (i = 0; i < count; i++) { index = (size_t) fi_addr[i]; if (index < av_priv->count) { if (av_priv->valid_entry_vec[index] == 0) { ret = -FI_EINVAL; break; } else { av_priv->valid_entry_vec[index] = 0; } } else { ret = -FI_EINVAL; break; } } return ret; } /* * table_lookup(): Translate fi_addr_t to struct gnix_address. */ static int table_lookup(struct gnix_fid_av *av_priv, fi_addr_t fi_addr, struct gnix_av_addr_entry *entry_ptr) { size_t index; struct gnix_av_addr_entry *entry = NULL; index = (size_t)fi_addr; if (index >= av_priv->count) return -FI_EINVAL; assert(av_priv->table); entry = &av_priv->table[index]; if (entry == NULL) return -FI_EINVAL; if (av_priv->valid_entry_vec[index] == 0) return -FI_EINVAL; memcpy(entry_ptr, entry, sizeof(*entry)); return FI_SUCCESS; } static int table_reverse_lookup(struct gnix_fid_av *av_priv, struct gnix_address gnix_addr, fi_addr_t *fi_addr) { struct gnix_av_addr_entry *entry; int i; for (i = 0; i < av_priv->count; i++) { entry = &av_priv->table[i]; /* * for SEP endpoint entry we may have a delta in the cdm_id * component of the address to process */ if ((entry->name_type & GNIX_EPN_TYPE_SEP) && (entry->gnix_addr.device_addr == gnix_addr.device_addr)) { int index = gnix_addr.cdm_id - entry->gnix_addr.cdm_id; if ((index >= 0) && (index < entry->rx_ctx_cnt)) { /* we have a match */ *fi_addr = fi_rx_addr(i, index, av_priv->rx_ctx_bits); return FI_SUCCESS; } } else if (GNIX_ADDR_EQUAL(entry->gnix_addr, gnix_addr)) { *fi_addr = i; return FI_SUCCESS; } } return -FI_ENOENT; } /******************************************************************************* * FI_AV_MAP specific implementations. ******************************************************************************/ 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++) { ret = _gnix_get_ep_name(addr, i, &ep_name, av_priv->domain); if (ret != FI_SUCCESS) { if (flags & FI_SYNC_ERR) { entry_err[i] = -FI_EINVAL; fi_addr[i] = FI_ADDR_NOTAVAIL; ret_cnt = -FI_EINVAL; continue; } else { return ret; } } /* 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; /* TODO: should try to do cleanup */ } } ((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; } /* * TODO: slab should be freed when entries in the slab drop to zero, * or as an alternative, have a free list for slabs so they can be * reused if new fi_av_insert operations are performed. */ static int map_remove(struct gnix_fid_av *av_priv, fi_addr_t *fi_addr, size_t count, uint64_t flags) { int i,ret = FI_SUCCESS; struct gnix_av_addr_entry *the_entry = NULL; gnix_ht_key_t key; for (i = 0; i < count; i++) { key = *(gnix_ht_key_t *)&fi_addr[i]; /* * first see if we have this entry in the hash * TODO: is there a race condition here for multi-threaded? */ the_entry = _gnix_ht_lookup(av_priv->map_ht, key); if (the_entry == NULL) return -FI_ENOENT; ret = _gnix_ht_remove(av_priv->map_ht, key); } return ret; } static int map_lookup(struct gnix_fid_av *av_priv, fi_addr_t fi_addr, struct gnix_av_addr_entry *entry_ptr) { gnix_ht_key_t *key = (gnix_ht_key_t *)&fi_addr; struct gnix_av_addr_entry *entry; entry = _gnix_ht_lookup(av_priv->map_ht, *key & av_priv->mask); if (entry == NULL) return -FI_ENOENT; memcpy(entry_ptr, entry, sizeof(*entry)); return FI_SUCCESS; } static int map_reverse_lookup(struct gnix_fid_av *av_priv, struct gnix_address gnix_addr, fi_addr_t *fi_addr) { GNIX_HASHTABLE_ITERATOR(av_priv->map_ht, iter); struct gnix_av_addr_entry *entry; fi_addr_t rx_addr; while ((entry = _gnix_ht_iterator_next(&iter))) { /* * for SEP endpoint entry we may have a delta in the cdm_id * component of the address to process */ if ((entry->name_type & GNIX_EPN_TYPE_SEP) && (entry->gnix_addr.device_addr == gnix_addr.device_addr)) { int index = gnix_addr.cdm_id - entry->gnix_addr.cdm_id; if ((index >= 0) && (index < entry->rx_ctx_cnt)) { /* we have a match */ memcpy(&rx_addr, &entry->gnix_addr, sizeof(fi_addr_t)); *fi_addr = fi_rx_addr(rx_addr, index, av_priv->rx_ctx_bits); return FI_SUCCESS; } } else { if (GNIX_ADDR_EQUAL(entry->gnix_addr, gnix_addr)) { *fi_addr = GNIX_HASHTABLE_ITERATOR_KEY(iter); return FI_SUCCESS; } } } return -FI_ENOENT; } /******************************************************************************* * FI_AV API implementations. ******************************************************************************/ int _gnix_table_reverse_lookup(struct gnix_fid_av *av_priv, struct gnix_address gnix_addr, fi_addr_t *fi_addr) { return table_reverse_lookup(av_priv, gnix_addr, fi_addr); } int _gnix_map_reverse_lookup(struct gnix_fid_av *av_priv, struct gnix_address gnix_addr, fi_addr_t *fi_addr) { return map_reverse_lookup(av_priv, gnix_addr, fi_addr); } int _gnix_av_lookup(struct gnix_fid_av *gnix_av, fi_addr_t fi_addr, struct gnix_av_addr_entry *entry_ptr) { int ret = FI_SUCCESS; fi_addr_t addr = fi_addr & gnix_av->mask; GNIX_TRACE(FI_LOG_AV, "\n"); if (!gnix_av) { ret = -FI_EINVAL; goto err; } switch (gnix_av->type) { case FI_AV_TABLE: ret = table_lookup(gnix_av, addr, entry_ptr); break; case FI_AV_MAP: ret = map_lookup(gnix_av, addr, entry_ptr); break; default: ret = -FI_EINVAL; break; } if (fi_addr & ~gnix_av->mask) { entry_ptr->gnix_addr.cdm_id += fi_addr >> (64 - gnix_av->rx_ctx_bits); } err: return ret; } int _gnix_av_reverse_lookup(struct gnix_fid_av *gnix_av, struct gnix_address gnix_addr, fi_addr_t *fi_addr) { int ret = FI_SUCCESS; GNIX_TRACE(FI_LOG_AV, "\n"); if (!gnix_av) { ret = -FI_EINVAL; goto err; } switch (gnix_av->type) { case FI_AV_TABLE: ret = table_reverse_lookup(gnix_av, gnix_addr, fi_addr); break; case FI_AV_MAP: ret = map_reverse_lookup(gnix_av, gnix_addr, fi_addr); break; default: ret = -FI_EINVAL; break; } err: return ret; } /* * Note: this function (according to WG), is not intended to * typically be used in the critical path for messaging/rma/amo * requests */ DIRECT_FN STATIC int gnix_av_lookup(struct fid_av *av, fi_addr_t fi_addr, void *addr, size_t *addrlen) { struct gnix_fid_av *gnix_av; struct gnix_ep_name ep_name = { {0} }; struct gnix_av_addr_entry entry; int ret; GNIX_TRACE(FI_LOG_AV, "\n"); if (!av || !addrlen) return -FI_EINVAL; gnix_av = container_of(av, struct gnix_fid_av, av_fid); if (gnix_av->domain->addr_format == FI_ADDR_STR) { if (*addrlen < GNIX_FI_ADDR_STR_LEN) { *addrlen = GNIX_FI_ADDR_STR_LEN; return -FI_ETOOSMALL; } } else { if (*addrlen < sizeof(ep_name)) { *addrlen = sizeof(ep_name); return -FI_ETOOSMALL; } } /* * user better have provided a buffer since the * value stored in addrlen is big enough to return ep_name */ if (!addr) return -FI_EINVAL; ret = _gnix_av_lookup(gnix_av, fi_addr, &entry); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_AV, "_gnix_av_lookup failed: %d\n", ret); return ret; } ep_name.gnix_addr = entry.gnix_addr; ep_name.name_type = entry.name_type; ep_name.cm_nic_cdm_id = entry.cm_nic_cdm_id; ep_name.cookie = entry.cookie; if (gnix_av->domain->addr_format == FI_ADDR_STR) { ret = _gnix_ep_name_to_str(&ep_name, (char **)&addr); if (ret != FI_SUCCESS) { GNIX_WARN(FI_LOG_AV, "_gnix_resolve_str_ep_name failed: %d %s\n", ret, fi_strerror(-ret)); return ret; } *addrlen = GNIX_FI_ADDR_STR_LEN; } else { memcpy(addr, (void *)&ep_name, MIN(*addrlen, sizeof(ep_name))); *addrlen = sizeof(ep_name); } return FI_SUCCESS; } DIRECT_FN STATIC int gnix_av_insert(struct fid_av *av, const void *addr, size_t count, fi_addr_t *fi_addr, uint64_t flags, void *context) { struct gnix_fid_av *av_priv = NULL; int ret = FI_SUCCESS; GNIX_TRACE(FI_LOG_AV, "\n"); if (!av) return -FI_EINVAL; av_priv = container_of(av, struct gnix_fid_av, av_fid); if (!av_priv) return -FI_EINVAL; if ((av_priv->type == FI_AV_MAP) && (fi_addr == NULL)) return -FI_EINVAL; if ((flags & FI_SYNC_ERR) && (context == NULL)) { GNIX_WARN(FI_LOG_AV, "FI_SYNC_ERR requires context\n"); return -FI_EINVAL; } switch (av_priv->type) { case FI_AV_TABLE: ret = table_insert(av_priv, addr, count, fi_addr, flags, context); break; case FI_AV_MAP: ret = map_insert(av_priv, addr, count, fi_addr, flags, context); break; default: ret = -FI_EINVAL; break; } return ret; } DIRECT_FN STATIC int gnix_av_insertsvc(struct fid_av *av, const char *node, const char *service, fi_addr_t *fi_addr, uint64_t flags, void *context) { return -FI_ENOSYS; } DIRECT_FN STATIC int gnix_av_insertsym(struct fid_av *av, const char *node, size_t nodecnt, const char *service, size_t svccnt, fi_addr_t *fi_addr, uint64_t flags, void *context) { return -FI_ENOSYS; } DIRECT_FN STATIC int gnix_av_remove(struct fid_av *av, fi_addr_t *fi_addr, size_t count, uint64_t flags) { struct gnix_fid_av *av_priv = NULL; int ret = FI_SUCCESS; GNIX_TRACE(FI_LOG_AV, "\n"); if (!av) { ret = -FI_EINVAL; goto err; } av_priv = container_of(av, struct gnix_fid_av, av_fid); if (!av_priv) { ret = -FI_EINVAL; goto err; } switch (av_priv->type) { case FI_AV_TABLE: ret = table_remove(av_priv, fi_addr, count, flags); break; case FI_AV_MAP: ret = map_remove(av_priv, fi_addr, count, flags); break; default: ret = -FI_EINVAL; break; } err: return ret; } /* * Given an address pointed to by addr, stuff a string into buf representing: * device_addr:cdm_id:name_type:cm_nic_cdm_id:cookie * where device_addr, cdm_id, cm_nic_cdm_id and cookie are represented in * hexadecimal. And name_type is represented as an integer. */ DIRECT_FN const char *gnix_av_straddr(struct fid_av *av, const void *addr, char *buf, size_t *len) { char int_buf[GNIX_AV_MAX_STR_ADDR_LEN]; int size; struct gnix_ep_name ep_name; struct gnix_fid_av *av_priv; if (!av || !addr || !buf || !len) { GNIX_DEBUG(FI_LOG_DEBUG, "NULL parameter in gnix_av_straddr\n"); return NULL; } av_priv = container_of(av, struct gnix_fid_av, av_fid); if (av_priv->domain->addr_format == FI_ADDR_STR) _gnix_resolve_str_ep_name(addr, 0, &ep_name); else ep_name = ((struct gnix_ep_name *) addr)[0]; /* * if additional information is added to this string, then * you will need to update in gnix.h: * GNIX_AV_STR_ADDR_VERSION, increment this value * GNIX_AV_MAX_STR_ADDR_LEN, to be the number of characters printed */ size = snprintf(int_buf, sizeof(int_buf), "%04i:0x%08" PRIx32 ":0x%08" PRIx32 ":%02i:0x%06" PRIx32 ":0x%08" PRIx32 ":%02i", GNIX_AV_STR_ADDR_VERSION, ep_name.gnix_addr.device_addr, ep_name.gnix_addr.cdm_id, ep_name.name_type, ep_name.cm_nic_cdm_id, ep_name.cookie, ep_name.rx_ctx_cnt); /* * snprintf returns the number of character written * without the terminating character. */ if ((size + 1) < *len) { /* * size needs to be all the characters plus the terminating * character. Otherwise, we could lose information. */ size = size + 1; } else { /* Do not overwrite the buffer. */ size = *len; } snprintf(buf, size, "%s", int_buf); *len = size; return buf; } static void __av_destruct(void *obj) { int ret; struct gnix_fid_av *av = (struct gnix_fid_av *) obj; struct slist_entry *blk_entry; struct gnix_av_block *temp; if (av->type == FI_AV_TABLE) { if (av->table) { free(av->table); } } else if (av->type == FI_AV_MAP) { while (!slist_empty(&av->block_list)) { blk_entry = slist_remove_head(&av->block_list); temp = container_of(blk_entry, struct gnix_av_block, slist); free(temp->base); free(temp); } ret = _gnix_ht_destroy(av->map_ht); if (ret != FI_SUCCESS) GNIX_WARN(FI_LOG_AV, "_gnix_ht_destroy failed %d\n", ret); free(av->map_ht); } if (av->valid_entry_vec) { free(av->valid_entry_vec); } else { GNIX_WARN(FI_LOG_AV, "valid_entry_vec is NULL\n"); } free(av); } static int gnix_av_close(fid_t fid) { struct gnix_fid_av *av = NULL; int ret = FI_SUCCESS; int references_held; GNIX_TRACE(FI_LOG_AV, "\n"); if (!fid) { ret = -FI_EINVAL; goto err; } av = container_of(fid, struct gnix_fid_av, av_fid.fid); references_held = _gnix_ref_put(av); if (references_held) { GNIX_INFO(FI_LOG_AV, "failed to fully close av due to lingering " "references. references=%i av=%p\n", references_held, av); } err: return ret; } DIRECT_FN int gnix_av_bind(struct fid_av *av, struct fid *fid, uint64_t flags) { return -FI_ENOSYS; } /* * TODO: Support shared named AVs. */ DIRECT_FN int gnix_av_open(struct fid_domain *domain, struct fi_av_attr *attr, struct fid_av **av, void *context) { struct gnix_fid_domain *int_dom = NULL; struct gnix_fid_av *av_priv = NULL; struct gnix_hashtable_attr ht_attr; enum fi_av_type type = FI_AV_TABLE; size_t count = 128; int rx_ctx_bits = 0; int ret = FI_SUCCESS; GNIX_TRACE(FI_LOG_AV, "\n"); if (!domain) { ret = -FI_EINVAL; goto err; } int_dom = container_of(domain, struct gnix_fid_domain, domain_fid); if (!int_dom) { ret = -FI_EINVAL; goto err; } av_priv = calloc(1, sizeof(*av_priv)); if (!av_priv) { ret = -FI_ENOMEM; goto err; } if (attr) { ret = gnix_verify_av_attr(attr); if (ret) { goto cleanup; } if (attr->type != FI_AV_UNSPEC) { type = attr->type; } count = attr->count; rx_ctx_bits = attr->rx_ctx_bits; } av_priv->domain = int_dom; av_priv->type = type; av_priv->addrlen = sizeof(struct gnix_address); av_priv->rx_ctx_bits = rx_ctx_bits; av_priv->mask = rx_ctx_bits ? ((uint64_t)1 << (64 - attr->rx_ctx_bits)) - 1 : ~0; av_priv->capacity = count; if (type == FI_AV_TABLE) { av_priv->table = calloc(count, sizeof(struct gnix_av_addr_entry)); if (!av_priv->table) { ret = -FI_ENOMEM; goto cleanup; } } av_priv->valid_entry_vec = calloc(count, sizeof(int)); if (!av_priv->valid_entry_vec) { ret = -FI_ENOMEM; goto cleanup; } av_priv->av_fid.fid.fclass = FI_CLASS_AV; av_priv->av_fid.fid.context = context; av_priv->av_fid.fid.ops = &gnix_fi_av_ops; av_priv->av_fid.ops = &gnix_av_ops; if (type == FI_AV_MAP) { av_priv->map_ht = calloc(1, sizeof(struct gnix_hashtable)); if (av_priv->map_ht == NULL) goto cleanup; /* * use same parameters as used for ep vc hash */ ht_attr.ht_initial_size = int_dom->params.ct_init_size; ht_attr.ht_maximum_size = int_dom->params.ct_max_size; ht_attr.ht_increase_step = int_dom->params.ct_step; ht_attr.ht_increase_type = GNIX_HT_INCREASE_MULT; ht_attr.ht_collision_thresh = 500; ht_attr.ht_hash_seed = 0xdeadbeefbeefdead; ht_attr.ht_internal_locking = 1; ht_attr.destructor = NULL; ret = _gnix_ht_init(av_priv->map_ht, &ht_attr); slist_init(&av_priv->block_list); } _gnix_ref_init(&av_priv->ref_cnt, 1, __av_destruct); *av = &av_priv->av_fid; return ret; cleanup: if (av_priv->table != NULL) free(av_priv->table); if (av_priv->valid_entry_vec != NULL) free(av_priv->valid_entry_vec); free(av_priv); err: return ret; } /******************************************************************************* * FI_OPS_* data structures. ******************************************************************************/ static struct fi_ops_av gnix_av_ops = { .size = sizeof(struct fi_ops_av), .insert = gnix_av_insert, .insertsvc = gnix_av_insertsvc, .insertsym = gnix_av_insertsym, .remove = gnix_av_remove, .lookup = gnix_av_lookup, .straddr = gnix_av_straddr }; static struct fi_ops gnix_fi_av_ops = { .size = sizeof(struct fi_ops), .close = gnix_av_close, .bind = fi_no_bind, .control = fi_no_control, .ops_open = fi_no_ops_open };