/**
 * Destroy a slab.
 *
 * @param[in] handle	Handle to the allocator being used.
 * @param[in] slab	Slab to be destroyed.
 *
 * @return FI_SUCCESS	On successful slab destruction.
 *
 * @return -FI_EINVAL	On invalid handle or slab being given as parameters.
 */
static int __destroy_slab(struct gnix_mbox_alloc_handle *handle,
			  struct gnix_slab *slab)
{
	size_t total_size;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	if (!handle || !slab) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Invalid argument handle or slab.\n");
		return -FI_EINVAL;
	}

	total_size = handle->page_size * __page_count(handle);

	_gnix_free_bitmap(slab->used);
	free(slab->used);

	COND_ACQUIRE(handle->nic_handle->requires_lock, &handle->nic_handle->lock);
	GNI_MemDeregister(handle->nic_handle->gni_nic_hndl,
			  &slab->memory_handle);
	COND_RELEASE(handle->nic_handle->requires_lock, &handle->nic_handle->lock);

	munmap(slab->base, total_size);

	free(slab);

	return FI_SUCCESS;
}
/**
 * Determine how many mboxes are in a requested allocation size.
 *
 * @param[in] handle	Handle to the allocator being used.
 *
 * @return Number of mail boxes being allocated.
 */
static size_t __mbox_count(struct gnix_mbox_alloc_handle *handle)
{
	size_t mbox_count = (__page_count(handle) * handle->page_size) /
			    handle->mbox_size;

	GNIX_DEBUG(FI_LOG_EP_CTRL,
		   "Mbox_count: %zu.\n", mbox_count);
	return mbox_count;
}
Example #3
0
/**
 * Fill all of the fields of an mbox to be returned to the requester.
 *
 * @param[in] handle	Handle to the allocator being used.
 * @param[in] slab	Slab which the mbox is allocated from.
 * @param[in] position	Position of the mbox in the slab.
 * @param[out] ptr	Contains the allocated mbox upon success.
 *
 * @return FI_SUCCESS	Upon successfully filling an mbox with relevant data.
 * @return -FI_EINVAL	Upon receiving invalid input, or finding the bitmap in
 * a corrupted state.
 * @return -FI_ENOMEM	Upon failure to create the mbox structure using calloc.
 */
static int __fill_mbox(struct gnix_mbox_alloc_handle *handle,
		       struct gnix_slab *slab, size_t position,
		       struct gnix_mbox **ptr)
{
	struct gnix_mbox *out;
	int ret = FI_SUCCESS;
	char error_buf[256];
	size_t mapped_size;
	char *error;

	out = calloc(1, sizeof(*out));
	if (!out) {
		error = strerror_r(errno, error_buf, sizeof(error_buf));
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Error allocating mbox: %s\n",
			  error);
		ret = -FI_ENOMEM;
		goto err_mbox_calloc;
	}

	mapped_size = handle->page_size * __page_count(handle);

	out->slab = slab;
	out->base = slab->base;
	out->offset = (position * handle->mbox_size);
	out->memory_handle = &slab->memory_handle;

	if (out->offset > mapped_size) {
		GNIX_WARN(FI_LOG_EP_CTRL, "Mbox out of bounds.\n");
		ret = -FI_EINVAL;
		goto err_invalid;
	}

	/* On some systems, the page may not be zero'd from first use.
		Memset it here */
	memset((void *) ((uint64_t) out->base + out->offset),
		0x0, handle->mbox_size);

	ret = _gnix_test_and_set_bit(slab->used, position);
	if (ret != 0) {
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Bit already set when creating mbox.\n");
		ret = -FI_EINVAL;
		goto err_invalid;
	}

	*ptr = out;

	return ret;

err_invalid:
	free(out);
err_mbox_calloc:
	return ret;
}
/**
 * Create a slab from a handle and append to the slab list.
 *
 * @param[in] handle	Handle to the allocator being used.
 *
 * @return FI_SUCCESS	On successful slab creation.
 *
 * @return -FI_ENOMEM	if failure to allocate memory for slab or bitmap.
 * @return [Unspec]	if failure in alloc_bitmap. Will return error code from
 * alloc_bitmap.
 * @return [Unspec]	if failure in GNI_MemRegister. Converts gni_return_t
 * status code to FI_ERRNO value.
 */
static int __create_slab(struct gnix_mbox_alloc_handle *handle)
{
	struct gnix_slab *slab;
	gni_return_t status;
	char error_buf[256];
	char *error;
	size_t total_size;
	int ret;
	int vmdh_index = -1;
	int flags = GNI_MEM_READWRITE;
	struct gnix_auth_key *info;

	GNIX_TRACE(FI_LOG_EP_CTRL, "\n");

	slab = calloc(1, sizeof(*slab));
	if (!slab) {
		error = strerror_r(errno, error_buf, sizeof(error_buf));
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Error allocating slab: %s\n",
			  error);
		ret = -FI_ENOMEM;
		goto err_slab_calloc;
	}

	total_size = handle->page_size * __page_count(handle);
	GNIX_DEBUG(FI_LOG_EP_CTRL, "total_size requested for mmap: %zu.\n",
		   total_size);

	slab->used = calloc(1, sizeof(*(slab->used)));
	if (!slab->used) {
		error = strerror_r(errno, error_buf, sizeof(error_buf));
		GNIX_WARN(FI_LOG_EP_CTRL,
			  "Error allocating bitmap: %s\n",
			  error);
		ret = -FI_ENOMEM;
		goto err_bitmap_calloc;
	}

	slab->base = mmap(0, total_size, (PROT_READ | PROT_WRITE), MAP_SHARED,
			  handle->fd, handle->last_offset);
	if (slab->base == MAP_FAILED) {
		error = strerror_r(errno, error_buf, sizeof(error_buf));
		GNIX_WARN(FI_LOG_EP_CTRL, "%s\n", error);
		ret = -FI_ENOMEM;
		goto err_mmap;
	}

	ret = _gnix_alloc_bitmap(slab->used, __mbox_count(handle), NULL);
	if (ret) {
		GNIX_WARN(FI_LOG_EP_CTRL, "Error allocating bitmap.\n");
		goto err_alloc_bitmap;
	}

	COND_ACQUIRE(handle->nic_handle->requires_lock, &handle->nic_handle->lock);
	if (handle->nic_handle->using_vmdh) {
		info = _gnix_auth_key_lookup(GNIX_PROV_DEFAULT_AUTH_KEY,
				GNIX_PROV_DEFAULT_AUTH_KEYLEN);
		assert(info);

		if (!handle->nic_handle->mdd_resources_set) {
			/* check to see if the ptag registration limit was set
			 * yet or not -- becomes read-only after success */
			_gnix_auth_key_enable(info);

			status = GNI_SetMddResources(
				handle->nic_handle->gni_nic_hndl,
				(info->attr.prov_key_limit +
				 info->attr.user_key_limit));
			assert(status == GNI_RC_SUCCESS);

			handle->nic_handle->mdd_resources_set = 1;
		}

		vmdh_index = _gnix_get_next_reserved_key(info);
		if (vmdh_index <= 0) {
			GNIX_FATAL(FI_LOG_DOMAIN,
				"failed to get reserved key for mbox "
				"registration, rc=%d\n",
				vmdh_index);
		}
		flags |= GNI_MEM_USE_VMDH;
	}

	status = GNI_MemRegister(handle->nic_handle->gni_nic_hndl,
				 (uint64_t) slab->base, total_size,
				 handle->cq_handle,
				 flags, vmdh_index,
				 &slab->memory_handle);
	COND_RELEASE(handle->nic_handle->requires_lock, &handle->nic_handle->lock);
	if (status != GNI_RC_SUCCESS) {
		GNIX_WARN(FI_LOG_EP_CTRL, "GNI_MemRegister failed: %s\n",
			  gni_err_str[status]);
		ret = gnixu_to_fi_errno(status);
		goto err_memregister;
	}

	slab->allocator = handle;

	gnix_slist_insert_tail(&slab->list_entry, &handle->slab_list);

	handle->last_offset += total_size;

	return ret;

err_memregister:
	_gnix_free_bitmap(slab->used);
err_alloc_bitmap:
	munmap(slab->base, total_size);
err_mmap:
	free(slab->used);
err_bitmap_calloc:
	free(slab);
err_slab_calloc:
	return ret;
}