/** * 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; }
/* 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); }
/** * 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; }
/** * 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; }