int _gnix_mr_reg()

in prov/gni/src/gnix_mr.c [200:335]


int _gnix_mr_reg(struct fid *fid, const void *buf, size_t len,
			  uint64_t access, uint64_t offset,
			  uint64_t requested_key, uint64_t flags,
			  struct fid_mr **mr_o, void *context,
			  struct gnix_auth_key *auth_key,
			  int reserved)
{
	struct gnix_fid_mem_desc *mr = NULL;
	struct gnix_fid_domain *domain;
	int rc;
	uint64_t reg_addr, reg_len;
	struct _gnix_fi_reg_context fi_reg_context = {
			.access = access,
			.offset = offset,
			.requested_key = requested_key,
			.flags = flags,
			.context = context,
			.auth_key = auth_key,
			.reserved = reserved,
	};
	struct gnix_mr_cache_info *info;

	GNIX_TRACE(FI_LOG_MR, "\n");

	GNIX_INFO(FI_LOG_MR, "reg: buf=%p len=%llu\n", buf, len);

	/* Flags are reserved for future use and must be 0. */
	if (OFI_UNLIKELY(flags))
		return -FI_EBADFLAGS;

	/* The offset parameter is reserved for future use and must be 0.
	 *   Additionally, check for invalid pointers, bad access flags and the
	 *   correct fclass on associated fid
	 */
	if (offset || !buf || !mr_o || !access ||
		(access & ~(FI_READ | FI_WRITE | FI_RECV | FI_SEND |
						FI_REMOTE_READ |
						FI_REMOTE_WRITE)) ||
		(fid->fclass != FI_CLASS_DOMAIN))
		return -FI_EINVAL;

	domain = container_of(fid, struct gnix_fid_domain, domain_fid.fid);

	if (auth_key->using_vmdh && !reserved &&
		requested_key >= auth_key->attr.user_key_limit)
		return -FI_EKEYREJECTED;

	if (!reserved && auth_key->using_vmdh) {
		/* adjust requested key by rank offset */
		fi_reg_context.requested_key += auth_key->key_offset;
		GNIX_DEBUG(FI_LOG_DOMAIN,
			"user requested key %d, but adjusting by "
			"rank offset as key %d\n",
			requested_key, fi_reg_context.requested_key);
	}

	if (auth_key->using_vmdh && !reserved &&
		requested_key < auth_key->attr.user_key_limit) {
		rc = _gnix_test_and_set_bit(auth_key->user,
				fi_reg_context.requested_key);
		if (rc) {
			GNIX_WARN(FI_LOG_DOMAIN, "key already in use, key=%d\n",
				fi_reg_context.requested_key);
			return -FI_ENOKEY;
		}
	}

	/* if this is a provider registration using VMDH and 0 was provided
	 * as the key, pick any available */
	if (auth_key->using_vmdh && reserved && !requested_key) {
		requested_key = _gnix_get_next_reserved_key(auth_key);
		if (requested_key <= 0)
			return -FI_ENOKEY;
		fi_reg_context.requested_key = requested_key;
	}

	info = &domain->mr_cache_info[auth_key->ptag];

	reg_addr = ((uint64_t) buf) & ~((1 << GNIX_MR_PAGE_SHIFT) - 1);
	reg_len = __calculate_length((uint64_t) buf, len,
			1 << GNIX_MR_PAGE_SHIFT);

	/* call cache register op to retrieve the right entry */
	fastlock_acquire(&info->mr_cache_lock);
	if (OFI_UNLIKELY(!domain->mr_ops))
		_gnix_open_cache(domain, GNIX_DEFAULT_CACHE_TYPE);

	if (OFI_UNLIKELY(!domain->mr_ops->is_init(domain, auth_key))) {
		rc = domain->mr_ops->init(domain, auth_key);
		if (rc != FI_SUCCESS) {
			fastlock_release(&info->mr_cache_lock);
			goto err;
		}
	}

	rc = domain->mr_ops->reg_mr(domain,
			(uint64_t) reg_addr, reg_len, &fi_reg_context,
			(void **) &mr);
	fastlock_release(&info->mr_cache_lock);

	/* check retcode */
	if (OFI_UNLIKELY(rc != FI_SUCCESS))
		goto err;

	/* md.mr_fid */
	mr->mr_fid.mem_desc = mr;
	mr->mr_fid.fid.fclass = FI_CLASS_MR;
	mr->mr_fid.fid.context = context;
	mr->mr_fid.fid.ops = &fi_gnix_mr_ops;

	/* setup internal key structure */
	mr->mr_fid.key = _gnix_convert_mhdl_to_key(&mr->mem_hndl);
	if (!reserved && auth_key->using_vmdh) {
		/* When using scalable, the key is a virtual index to the
		   vmdh table */
		mr->mr_fid.key = requested_key;
	}
	mr->auth_key = auth_key;

	if (reserved && auth_key->using_vmdh) {
		rc = __gnix_mr_refresh(mr, reg_addr, reg_len);
		if (rc != FI_SUCCESS)
			GNIX_FATAL(FI_LOG_MR,
				"failed to enabled internal provider registration, ret=%d",
				rc);
	}

	_gnix_ref_get(mr->domain);

	/* set up mr_o out pointer */
	*mr_o = &mr->mr_fid;
	return FI_SUCCESS;

err:
	return rc;
}