/** * 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; }
void lnet_finalize (__unusedx lnet_ni_t *ni, lnet_msg_t *msg, int status) { #ifdef __KERNEL__ int i; int my_slot; #endif lnet_libmd_t *md; LASSERT (!in_interrupt ()); if (msg == NULL) return; #if 0 CDEBUG(D_WARNING, "%s msg->%s Flags:%s%s%s%s%s%s%s%s%s%s%s txp %s rxp %s\n", lnet_msgtyp2str(msg->msg_type), libcfs_id2str(msg->msg_target), msg->msg_target_is_router ? "t" : "", msg->msg_routing ? "X" : "", msg->msg_ack ? "A" : "", msg->msg_sending ? "S" : "", msg->msg_receiving ? "R" : "", msg->msg_delayed ? "d" : "", msg->msg_txcredit ? "C" : "", msg->msg_peertxcredit ? "c" : "", msg->msg_rtrcredit ? "F" : "", msg->msg_peerrtrcredit ? "f" : "", msg->msg_onactivelist ? "!" : "", msg->msg_txpeer == NULL ? "<none>" : libcfs_nid2str(msg->msg_txpeer->lp_nid), msg->msg_rxpeer == NULL ? "<none>" : libcfs_nid2str(msg->msg_rxpeer->lp_nid)); #endif LNET_LOCK(); LASSERT (msg->msg_onactivelist); msg->msg_ev.status = status; md = msg->msg_md; if (md != NULL) { int unlink; /* Now it's safe to drop my caller's ref */ md->md_refcount--; LASSERT (md->md_refcount >= 0); unlink = lnet_md_unlinkable(md); msg->msg_ev.unlinked = unlink; if (md->md_eq != NULL) lnet_enq_event_locked(md->md_eq, &msg->msg_ev); if (unlink) lnet_md_unlink(md); msg->msg_md = NULL; } list_add_tail (&msg->msg_list, &the_lnet.ln_finalizeq); /* Recursion breaker. Don't complete the message here if I am (or * enough other threads are) already completing messages */ #ifdef __KERNEL__ my_slot = -1; for (i = 0; i < the_lnet.ln_nfinalizers; i++) { if (the_lnet.ln_finalizers[i] == cfs_current()) goto out; if (my_slot < 0 && the_lnet.ln_finalizers[i] == NULL) my_slot = i; } if (my_slot < 0) goto out; the_lnet.ln_finalizers[my_slot] = cfs_current(); #else if (the_lnet.ln_finalizing) goto out; the_lnet.ln_finalizing = 1; #endif while (!list_empty(&the_lnet.ln_finalizeq)) { msg = list_entry(the_lnet.ln_finalizeq.next, lnet_msg_t, msg_list); list_del(&msg->msg_list); /* NB drops and regains the lnet lock if it actually does * anything, so my finalizing friends can chomp along too */ lnet_complete_msg_locked(msg); } #ifdef __KERNEL__ the_lnet.ln_finalizers[my_slot] = NULL; #else the_lnet.ln_finalizing = 0; #endif out: LNET_UNLOCK(); }