Example #1
0
/**
 * Unlink the memory descriptor from any ME it may be linked to and release
 * the internal resources associated with it. As a result, active messages
 * associated with the MD may get aborted.
 *
 * This function does not free the memory region associated with the MD;
 * i.e., the memory the user allocated for this MD. If the ME associated with
 * this MD is not NULL and was created with auto unlink enabled, the ME is
 * unlinked as well (see LNetMEAttach()).
 *
 * Explicitly unlinking a MD via this function call has the same behavior as
 * a MD that has been automatically unlinked, except that no LNET_EVENT_UNLINK
 * is generated in the latter case.
 *
 * An unlinked event can be reported in two ways:
 * - If there's no pending operations on the MD, it's unlinked immediately
 *   and an LNET_EVENT_UNLINK event is logged before this function returns.
 * - Otherwise, the MD is only marked for deletion when this function
 *   returns, and the unlinked event will be piggybacked on the event of
 *   the completion of the last operation by setting the unlinked field of
 *   the event. No dedicated LNET_EVENT_UNLINK event is generated.
 *
 * Note that in both cases the unlinked field of the event is always set; no
 * more event will happen on the MD after such an event is logged.
 *
 * \param mdh A handle for the MD to be unlinked.
 *
 * \retval 0       On success.
 * \retval -ENOENT If \a mdh does not point to a valid MD object.
 */
int
LNetMDUnlink (lnet_handle_md_t mdh)
{
	lnet_event_t	ev;
	lnet_libmd_t	*md;
	int		cpt;

	LASSERT(the_lnet.ln_init);
	LASSERT(the_lnet.ln_refcount > 0);

	cpt = lnet_cpt_of_cookie(mdh.cookie);
	lnet_res_lock(cpt);

	md = lnet_handle2md(&mdh);
	if (md == NULL) {
		lnet_res_unlock(cpt);
                return -ENOENT;
        }

	md->md_flags |= LNET_MD_FLAG_ABORTED;
	/* If the MD is busy, lnet_md_unlink just marks it for deletion, and
	 * when the LND is done, the completion event flags that the MD was
	 * unlinked. Otherwise, we enqueue an event now... */
	if (md->md_eq != NULL && md->md_refcount == 0) {
		lnet_build_unlink_event(md, &ev);
		lnet_eq_enqueue_event(md->md_eq, &ev);
	}

        lnet_md_unlink(md);

	lnet_res_unlock(cpt);
	return 0;
}
Example #2
0
/* must be called with lnet_res_lock held */
void
lnet_md_unlink(struct lnet_libmd *md)
{
	if (!(md->md_flags & LNET_MD_FLAG_ZOMBIE)) {
		/* first unlink attempt... */
		struct lnet_me *me = md->md_me;

		md->md_flags |= LNET_MD_FLAG_ZOMBIE;

		/*
		 * Disassociate from ME (if any),
		 * and unlink it if it was created
		 * with LNET_UNLINK
		 */
		if (me) {
			/* detach MD from portal */
			lnet_ptl_detach_md(me, md);
			if (me->me_unlink == LNET_UNLINK)
				lnet_me_unlink(me);
		}

		/* ensure all future handle lookups fail */
		lnet_res_lh_invalidate(&md->md_lh);
	}

	if (md->md_refcount) {
		CDEBUG(D_NET, "Queueing unlink of md %p\n", md);
		return;
	}

	CDEBUG(D_NET, "Unlinking md %p\n", md);

	if (md->md_eq) {
		int cpt = lnet_cpt_of_cookie(md->md_lh.lh_cookie);

		LASSERT(*md->md_eq->eq_refs[cpt] > 0);
		(*md->md_eq->eq_refs[cpt])--;
	}

	LASSERT(!list_empty(&md->md_list));
	list_del_init(&md->md_list);
	lnet_md_free(md);
}
Example #3
0
/**
 * Create a memory descriptor and attach it to a ME
 *
 * \param meh A handle for a ME to associate the new MD with.
 * \param umd Provides initial values for the user-visible parts of a MD.
 * Other than its use for initialization, there is no linkage between this
 * structure and the MD maintained by the LNet.
 * \param unlink A flag to indicate whether the MD is automatically unlinked
 * when it becomes inactive, either because the operation threshold drops to
 * zero or because the available memory becomes less than \a umd.max_size.
 * (Note that the check for unlinking a MD only occurs after the completion
 * of a successful operation on the MD.) The value LNET_UNLINK enables auto
 * unlinking; the value LNET_RETAIN disables it.
 * \param handle On successful returns, a handle to the newly created MD is
 * saved here. This handle can be used later in LNetMDUnlink().
 *
 * \retval 0       On success.
 * \retval -EINVAL If \a umd is not valid.
 * \retval -ENOMEM If new MD cannot be allocated.
 * \retval -ENOENT Either \a meh or \a umd.eq_handle does not point to a
 * valid object. Note that it's OK to supply a NULL \a umd.eq_handle by
 * calling LNetInvalidateHandle() on it.
 * \retval -EBUSY  If the ME pointed to by \a meh is already associated with
 * a MD.
 */
int
LNetMDAttach(lnet_handle_me_t meh, lnet_md_t umd,
	     lnet_unlink_t unlink, lnet_handle_md_t *handle)
{
	CFS_LIST_HEAD		(matches);
	CFS_LIST_HEAD		(drops);
	struct lnet_me		*me;
	struct lnet_libmd	*md;
	int			cpt;
	int			rc;

        LASSERT (the_lnet.ln_init);
        LASSERT (the_lnet.ln_refcount > 0);

        if (lnet_md_validate(&umd) != 0)
                return -EINVAL;

        if ((umd.options & (LNET_MD_OP_GET | LNET_MD_OP_PUT)) == 0) {
                CERROR("Invalid option: no MD_OP set\n");
                return -EINVAL;
        }

        md = lnet_md_alloc(&umd);
        if (md == NULL)
                return -ENOMEM;

	rc = lnet_md_build(md, &umd, unlink);
	cpt = lnet_cpt_of_cookie(meh.cookie);

	lnet_res_lock(cpt);
	if (rc != 0)
		goto failed;

	me = lnet_handle2me(&meh);
	if (me == NULL)
		rc = -ENOENT;
	else if (me->me_md != NULL)
		rc = -EBUSY;
	else
		rc = lnet_md_link(md, umd.eq_handle, cpt);

	if (rc != 0)
		goto failed;

	/* attach this MD to portal of ME and check if it matches any
	 * blocked msgs on this portal */
	lnet_ptl_attach_md(me, md, &matches, &drops);

	lnet_md2handle(handle, md);

	lnet_res_unlock(cpt);

	lnet_drop_delayed_msg_list(&drops, "Bad match");
	lnet_recv_delayed_msg_list(&matches);

	return 0;

 failed:
	lnet_md_free_locked(md);

	lnet_res_unlock(cpt);
	return rc;
}
Example #4
0
/**
 * Create a memory descriptor and attach it to a ME
 *
 * \param meh A handle for a ME to associate the new MD with.
 * \param umd Provides initial values for the user-visible parts of a MD.
 * Other than its use for initialization, there is no linkage between this
 * structure and the MD maintained by the LNet.
 * \param unlink A flag to indicate whether the MD is automatically unlinked
 * when it becomes inactive, either because the operation threshold drops to
 * zero or because the available memory becomes less than \a umd.max_size.
 * (Note that the check for unlinking a MD only occurs after the completion
 * of a successful operation on the MD.) The value LNET_UNLINK enables auto
 * unlinking; the value LNET_RETAIN disables it.
 * \param handle On successful returns, a handle to the newly created MD is
 * saved here. This handle can be used later in LNetMDUnlink().
 *
 * \retval 0       On success.
 * \retval -EINVAL If \a umd is not valid.
 * \retval -ENOMEM If new MD cannot be allocated.
 * \retval -ENOENT Either \a meh or \a umd.eq_handle does not point to a
 * valid object. Note that it's OK to supply a NULL \a umd.eq_handle by
 * calling LNetInvalidateHandle() on it.
 * \retval -EBUSY  If the ME pointed to by \a meh is already associated with
 * a MD.
 */
int
LNetMDAttach(struct lnet_handle_me meh, struct lnet_md umd,
	     enum lnet_unlink unlink, struct lnet_handle_md *handle)
{
	LIST_HEAD(matches);
	LIST_HEAD(drops);
	struct lnet_me *me;
	struct lnet_libmd *md;
	int cpt;
	int rc;

	LASSERT(the_lnet.ln_refcount > 0);

	if (lnet_md_validate(&umd))
		return -EINVAL;

	if (!(umd.options & (LNET_MD_OP_GET | LNET_MD_OP_PUT))) {
		CERROR("Invalid option: no MD_OP set\n");
		return -EINVAL;
	}

	md = lnet_md_alloc(&umd);
	if (!md)
		return -ENOMEM;

	rc = lnet_md_build(md, &umd, unlink);
	if (rc)
		goto out_free;

	cpt = lnet_cpt_of_cookie(meh.cookie);

	lnet_res_lock(cpt);

	me = lnet_handle2me(&meh);
	if (!me)
		rc = -ENOENT;
	else if (me->me_md)
		rc = -EBUSY;
	else
		rc = lnet_md_link(md, umd.eq_handle, cpt);

	if (rc)
		goto out_unlock;

	/*
	 * attach this MD to portal of ME and check if it matches any
	 * blocked msgs on this portal
	 */
	lnet_ptl_attach_md(me, md, &matches, &drops);

	lnet_md2handle(handle, md);

	lnet_res_unlock(cpt);

	lnet_drop_delayed_msg_list(&drops, "Bad match");
	lnet_recv_delayed_msg_list(&matches);

	return 0;

out_unlock:
	lnet_res_unlock(cpt);
out_free:
	lnet_md_free(md);
	return rc;
}