| 1 | /* |
| 2 | * GPL HEADER START |
| 3 | * |
| 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License version 2 only, |
| 8 | * as published by the Free Software Foundation. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, but |
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 13 | * General Public License version 2 for more details (a copy is included |
| 14 | * in the LICENSE file that accompanied this code). |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * version 2 along with this program; If not, see |
| 18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf |
| 19 | * |
| 20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 21 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 22 | * have any questions. |
| 23 | * |
| 24 | * GPL HEADER END |
| 25 | */ |
| 26 | /* |
| 27 | * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. |
| 28 | * Use is subject to license terms. |
| 29 | * |
| 30 | * Copyright (c) 2012, Intel Corporation. |
| 31 | */ |
| 32 | /* |
| 33 | * This file is part of Lustre, http://www.lustre.org/ |
| 34 | * Lustre is a trademark of Sun Microsystems, Inc. |
| 35 | * |
| 36 | * lnet/lnet/lib-me.c |
| 37 | * |
| 38 | * Match Entry management routines |
| 39 | */ |
| 40 | |
| 41 | #define DEBUG_SUBSYSTEM S_LNET |
| 42 | |
| 43 | #include "../../include/linux/lnet/lib-lnet.h" |
| 44 | |
| 45 | /** |
| 46 | * Create and attach a match entry to the match list of \a portal. The new |
| 47 | * ME is empty, i.e. not associated with a memory descriptor. LNetMDAttach() |
| 48 | * can be used to attach a MD to an empty ME. |
| 49 | * |
| 50 | * \param portal The portal table index where the ME should be attached. |
| 51 | * \param match_id Specifies the match criteria for the process ID of |
| 52 | * the requester. The constants LNET_PID_ANY and LNET_NID_ANY can be |
| 53 | * used to wildcard either of the identifiers in the lnet_process_id_t |
| 54 | * structure. |
| 55 | * \param match_bits,ignore_bits Specify the match criteria to apply |
| 56 | * to the match bits in the incoming request. The ignore bits are used |
| 57 | * to mask out insignificant bits in the incoming match bits. The resulting |
| 58 | * bits are then compared to the ME's match bits to determine if the |
| 59 | * incoming request meets the match criteria. |
| 60 | * \param unlink Indicates whether the ME should be unlinked when the memory |
| 61 | * descriptor associated with it is unlinked (Note that the check for |
| 62 | * unlinking a ME only occurs when the memory descriptor is unlinked.). |
| 63 | * Valid values are LNET_RETAIN and LNET_UNLINK. |
| 64 | * \param pos Indicates whether the new ME should be prepended or |
| 65 | * appended to the match list. Allowed constants: LNET_INS_BEFORE, |
| 66 | * LNET_INS_AFTER. |
| 67 | * \param handle On successful returns, a handle to the newly created ME |
| 68 | * object is saved here. This handle can be used later in LNetMEInsert(), |
| 69 | * LNetMEUnlink(), or LNetMDAttach() functions. |
| 70 | * |
| 71 | * \retval 0 On success. |
| 72 | * \retval -EINVAL If \a portal is invalid. |
| 73 | * \retval -ENOMEM If new ME object cannot be allocated. |
| 74 | */ |
| 75 | int |
| 76 | LNetMEAttach(unsigned int portal, |
| 77 | lnet_process_id_t match_id, |
| 78 | __u64 match_bits, __u64 ignore_bits, |
| 79 | lnet_unlink_t unlink, lnet_ins_pos_t pos, |
| 80 | lnet_handle_me_t *handle) |
| 81 | { |
| 82 | struct lnet_match_table *mtable; |
| 83 | struct lnet_me *me; |
| 84 | struct list_head *head; |
| 85 | |
| 86 | LASSERT(the_lnet.ln_init); |
| 87 | LASSERT(the_lnet.ln_refcount > 0); |
| 88 | |
| 89 | if ((int)portal >= the_lnet.ln_nportals) |
| 90 | return -EINVAL; |
| 91 | |
| 92 | mtable = lnet_mt_of_attach(portal, match_id, |
| 93 | match_bits, ignore_bits, pos); |
| 94 | if (mtable == NULL) /* can't match portal type */ |
| 95 | return -EPERM; |
| 96 | |
| 97 | me = lnet_me_alloc(); |
| 98 | if (me == NULL) |
| 99 | return -ENOMEM; |
| 100 | |
| 101 | lnet_res_lock(mtable->mt_cpt); |
| 102 | |
| 103 | me->me_portal = portal; |
| 104 | me->me_match_id = match_id; |
| 105 | me->me_match_bits = match_bits; |
| 106 | me->me_ignore_bits = ignore_bits; |
| 107 | me->me_unlink = unlink; |
| 108 | me->me_md = NULL; |
| 109 | |
| 110 | lnet_res_lh_initialize(the_lnet.ln_me_containers[mtable->mt_cpt], |
| 111 | &me->me_lh); |
| 112 | if (ignore_bits != 0) |
| 113 | head = &mtable->mt_mhash[LNET_MT_HASH_IGNORE]; |
| 114 | else |
| 115 | head = lnet_mt_match_head(mtable, match_id, match_bits); |
| 116 | |
| 117 | me->me_pos = head - &mtable->mt_mhash[0]; |
| 118 | if (pos == LNET_INS_AFTER || pos == LNET_INS_LOCAL) |
| 119 | list_add_tail(&me->me_list, head); |
| 120 | else |
| 121 | list_add(&me->me_list, head); |
| 122 | |
| 123 | lnet_me2handle(handle, me); |
| 124 | |
| 125 | lnet_res_unlock(mtable->mt_cpt); |
| 126 | return 0; |
| 127 | } |
| 128 | EXPORT_SYMBOL(LNetMEAttach); |
| 129 | |
| 130 | /** |
| 131 | * Create and a match entry and insert it before or after the ME pointed to by |
| 132 | * \a current_meh. The new ME is empty, i.e. not associated with a memory |
| 133 | * descriptor. LNetMDAttach() can be used to attach a MD to an empty ME. |
| 134 | * |
| 135 | * This function is identical to LNetMEAttach() except for the position |
| 136 | * where the new ME is inserted. |
| 137 | * |
| 138 | * \param current_meh A handle for a ME. The new ME will be inserted |
| 139 | * immediately before or immediately after this ME. |
| 140 | * \param match_id,match_bits,ignore_bits,unlink,pos,handle See the discussion |
| 141 | * for LNetMEAttach(). |
| 142 | * |
| 143 | * \retval 0 On success. |
| 144 | * \retval -ENOMEM If new ME object cannot be allocated. |
| 145 | * \retval -ENOENT If \a current_meh does not point to a valid match entry. |
| 146 | */ |
| 147 | int |
| 148 | LNetMEInsert(lnet_handle_me_t current_meh, |
| 149 | lnet_process_id_t match_id, |
| 150 | __u64 match_bits, __u64 ignore_bits, |
| 151 | lnet_unlink_t unlink, lnet_ins_pos_t pos, |
| 152 | lnet_handle_me_t *handle) |
| 153 | { |
| 154 | struct lnet_me *current_me; |
| 155 | struct lnet_me *new_me; |
| 156 | struct lnet_portal *ptl; |
| 157 | int cpt; |
| 158 | |
| 159 | LASSERT(the_lnet.ln_init); |
| 160 | LASSERT(the_lnet.ln_refcount > 0); |
| 161 | |
| 162 | if (pos == LNET_INS_LOCAL) |
| 163 | return -EPERM; |
| 164 | |
| 165 | new_me = lnet_me_alloc(); |
| 166 | if (new_me == NULL) |
| 167 | return -ENOMEM; |
| 168 | |
| 169 | cpt = lnet_cpt_of_cookie(current_meh.cookie); |
| 170 | |
| 171 | lnet_res_lock(cpt); |
| 172 | |
| 173 | current_me = lnet_handle2me(¤t_meh); |
| 174 | if (current_me == NULL) { |
| 175 | lnet_me_free_locked(new_me); |
| 176 | |
| 177 | lnet_res_unlock(cpt); |
| 178 | return -ENOENT; |
| 179 | } |
| 180 | |
| 181 | LASSERT(current_me->me_portal < the_lnet.ln_nportals); |
| 182 | |
| 183 | ptl = the_lnet.ln_portals[current_me->me_portal]; |
| 184 | if (lnet_ptl_is_unique(ptl)) { |
| 185 | /* nosense to insertion on unique portal */ |
| 186 | lnet_me_free_locked(new_me); |
| 187 | lnet_res_unlock(cpt); |
| 188 | return -EPERM; |
| 189 | } |
| 190 | |
| 191 | new_me->me_pos = current_me->me_pos; |
| 192 | new_me->me_portal = current_me->me_portal; |
| 193 | new_me->me_match_id = match_id; |
| 194 | new_me->me_match_bits = match_bits; |
| 195 | new_me->me_ignore_bits = ignore_bits; |
| 196 | new_me->me_unlink = unlink; |
| 197 | new_me->me_md = NULL; |
| 198 | |
| 199 | lnet_res_lh_initialize(the_lnet.ln_me_containers[cpt], &new_me->me_lh); |
| 200 | |
| 201 | if (pos == LNET_INS_AFTER) |
| 202 | list_add(&new_me->me_list, ¤t_me->me_list); |
| 203 | else |
| 204 | list_add_tail(&new_me->me_list, ¤t_me->me_list); |
| 205 | |
| 206 | lnet_me2handle(handle, new_me); |
| 207 | |
| 208 | lnet_res_unlock(cpt); |
| 209 | |
| 210 | return 0; |
| 211 | } |
| 212 | EXPORT_SYMBOL(LNetMEInsert); |
| 213 | |
| 214 | /** |
| 215 | * Unlink a match entry from its match list. |
| 216 | * |
| 217 | * This operation also releases any resources associated with the ME. If a |
| 218 | * memory descriptor is attached to the ME, then it will be unlinked as well |
| 219 | * and an unlink event will be generated. It is an error to use the ME handle |
| 220 | * after calling LNetMEUnlink(). |
| 221 | * |
| 222 | * \param meh A handle for the ME to be unlinked. |
| 223 | * |
| 224 | * \retval 0 On success. |
| 225 | * \retval -ENOENT If \a meh does not point to a valid ME. |
| 226 | * \see LNetMDUnlink() for the discussion on delivering unlink event. |
| 227 | */ |
| 228 | int |
| 229 | LNetMEUnlink(lnet_handle_me_t meh) |
| 230 | { |
| 231 | lnet_me_t *me; |
| 232 | lnet_libmd_t *md; |
| 233 | lnet_event_t ev; |
| 234 | int cpt; |
| 235 | |
| 236 | LASSERT(the_lnet.ln_init); |
| 237 | LASSERT(the_lnet.ln_refcount > 0); |
| 238 | |
| 239 | cpt = lnet_cpt_of_cookie(meh.cookie); |
| 240 | lnet_res_lock(cpt); |
| 241 | |
| 242 | me = lnet_handle2me(&meh); |
| 243 | if (me == NULL) { |
| 244 | lnet_res_unlock(cpt); |
| 245 | return -ENOENT; |
| 246 | } |
| 247 | |
| 248 | md = me->me_md; |
| 249 | if (md != NULL) { |
| 250 | md->md_flags |= LNET_MD_FLAG_ABORTED; |
| 251 | if (md->md_eq != NULL && md->md_refcount == 0) { |
| 252 | lnet_build_unlink_event(md, &ev); |
| 253 | lnet_eq_enqueue_event(md->md_eq, &ev); |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | lnet_me_unlink(me); |
| 258 | |
| 259 | lnet_res_unlock(cpt); |
| 260 | return 0; |
| 261 | } |
| 262 | EXPORT_SYMBOL(LNetMEUnlink); |
| 263 | |
| 264 | /* call with lnet_res_lock please */ |
| 265 | void |
| 266 | lnet_me_unlink(lnet_me_t *me) |
| 267 | { |
| 268 | list_del(&me->me_list); |
| 269 | |
| 270 | if (me->me_md != NULL) { |
| 271 | lnet_libmd_t *md = me->me_md; |
| 272 | |
| 273 | /* detach MD from portal of this ME */ |
| 274 | lnet_ptl_detach_md(me, md); |
| 275 | lnet_md_unlink(md); |
| 276 | } |
| 277 | |
| 278 | lnet_res_lh_invalidate(&me->me_lh); |
| 279 | lnet_me_free_locked(me); |
| 280 | } |
| 281 | |
| 282 | #if 0 |
| 283 | static void |
| 284 | lib_me_dump(lnet_me_t *me) |
| 285 | { |
| 286 | CWARN("Match Entry %p (%#llx)\n", me, |
| 287 | me->me_lh.lh_cookie); |
| 288 | |
| 289 | CWARN("\tMatch/Ignore\t= %016lx / %016lx\n", |
| 290 | me->me_match_bits, me->me_ignore_bits); |
| 291 | |
| 292 | CWARN("\tMD\t= %p\n", me->md); |
| 293 | CWARN("\tprev\t= %p\n", |
| 294 | list_entry(me->me_list.prev, lnet_me_t, me_list)); |
| 295 | CWARN("\tnext\t= %p\n", |
| 296 | list_entry(me->me_list.next, lnet_me_t, me_list)); |
| 297 | } |
| 298 | #endif |