Whamcloud - gitweb
b=20973 Doxygen comments for LNet API
[fs/lustre-release.git] / lnet / lnet / lib-me.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
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 <lnet/lib-lnet.h>
44
45 static int
46 lnet_me_match_portal(lnet_portal_t *ptl, lnet_process_id_t id,
47                      __u64 match_bits, __u64 ignore_bits)
48 {
49         cfs_list_t       *mhash = NULL;
50         int               unique;
51
52         LASSERT (!(lnet_portal_is_unique(ptl) &&
53                    lnet_portal_is_wildcard(ptl)));
54
55         /* prefer to check w/o any lock */
56         unique = lnet_match_is_unique(id, match_bits, ignore_bits);
57         if (likely(lnet_portal_is_unique(ptl) ||
58                    lnet_portal_is_wildcard(ptl)))
59                 goto match;
60
61         /* unset, new portal */
62         if (unique) {
63                 mhash = lnet_portal_mhash_alloc();
64                 if (mhash == NULL)
65                         return -ENOMEM;
66         }
67
68         LNET_LOCK();
69         if (lnet_portal_is_unique(ptl) ||
70             lnet_portal_is_wildcard(ptl)) {
71                 /* someone set it before me */
72                 if (mhash != NULL)
73                         lnet_portal_mhash_free(mhash);
74                 LNET_UNLOCK();
75                 goto match;
76         }
77
78         /* still not set */
79         LASSERT (ptl->ptl_mhash == NULL);
80         if (unique) {
81                 ptl->ptl_mhash = mhash;
82                 lnet_portal_setopt(ptl, LNET_PTL_MATCH_UNIQUE);
83         } else {
84                 lnet_portal_setopt(ptl, LNET_PTL_MATCH_WILDCARD);
85         }
86         LNET_UNLOCK();
87         return 0;
88
89  match:
90         if (lnet_portal_is_unique(ptl) && !unique)
91                 return -EPERM;
92
93         if (lnet_portal_is_wildcard(ptl) && unique)
94                 return -EPERM;
95
96         return 0;
97 }
98
99 /**
100  * Create and attach a match entry to the match list of \a portal. The new
101  * ME is empty, i.e. not associated with a memory descriptor. LNetMDAttach()
102  * can be used to attach a MD to an empty ME.
103  *
104  * \param portal The portal table index where the ME should be attached.
105  * \param match_id Specifies the match criteria for the process ID of
106  * the requester. The constants LNET_PID_ANY and LNET_NID_ANY can be
107  * used to wildcard either of the identifiers in the lnet_process_id_t
108  * structure.
109  * \param match_bits,ignore_bits Specify the match criteria to apply
110  * to the match bits in the incoming request. The ignore bits are used
111  * to mask out insignificant bits in the incoming match bits. The resulting
112  * bits are then compared to the ME's match bits to determine if the
113  * incoming request meets the match criteria.
114  * \param unlink Indicates whether the ME should be unlinked when the memory
115  * descriptor associated with it is unlinked (Note that the check for
116  * unlinking a ME only occurs when the memory descriptor is unlinked.).
117  * Valid values are LNET_RETAIN and LNET_UNLINK.
118  * \param pos Indicates whether the new ME should be prepended or
119  * appended to the match list. Allowed constants: LNET_INS_BEFORE,
120  * LNET_INS_AFTER.
121  * \param handle On successful returns, a handle to the newly created ME
122  * object is saved here. This handle can be used later in LNetMEInsert(),
123  * LNetMEUnlink(), or LNetMDAttach() functions.
124  *
125  * \retval 0       On success.
126  * \retval -EINVAL If \a portal is invalid.
127  * \retval -ENOMEM If new ME object cannot be allocated.
128  */
129 int
130 LNetMEAttach(unsigned int portal,
131              lnet_process_id_t match_id,
132              __u64 match_bits, __u64 ignore_bits,
133              lnet_unlink_t unlink, lnet_ins_pos_t pos,
134              lnet_handle_me_t *handle)
135 {
136         lnet_me_t        *me;
137         lnet_portal_t    *ptl;
138         cfs_list_t       *head;
139         int               rc;
140
141         LASSERT (the_lnet.ln_init);
142         LASSERT (the_lnet.ln_refcount > 0);
143
144         if ((int)portal >= the_lnet.ln_nportals)
145                 return -EINVAL;
146
147         ptl = &the_lnet.ln_portals[portal];
148         rc = lnet_me_match_portal(ptl, match_id, match_bits, ignore_bits);
149         if (rc != 0)
150                 return rc;
151
152         me = lnet_me_alloc();
153         if (me == NULL)
154                 return -ENOMEM;
155
156         LNET_LOCK();
157
158         me->me_portal = portal;
159         me->me_match_id = match_id;
160         me->me_match_bits = match_bits;
161         me->me_ignore_bits = ignore_bits;
162         me->me_unlink = unlink;
163         me->me_md = NULL;
164
165         lnet_initialise_handle (&me->me_lh, LNET_COOKIE_TYPE_ME);
166         head = lnet_portal_me_head(portal, match_id, match_bits);
167         LASSERT (head != NULL);
168
169         if (pos == LNET_INS_AFTER)
170                 cfs_list_add_tail(&me->me_list, head);
171         else
172                 cfs_list_add(&me->me_list, head);
173
174         lnet_me2handle(handle, me);
175
176         LNET_UNLOCK();
177
178         return 0;
179 }
180
181 /**
182  * Create and a match entry and insert it before or after the ME pointed to by
183  * \a current_meh. The new ME is empty, i.e. not associated with a memory
184  * descriptor. LNetMDAttach() can be used to attach a MD to an empty ME.
185  *
186  * This function is identical to LNetMEAttach() except for the position
187  * where the new ME is inserted.
188  *
189  * \param current_meh A handle for a ME. The new ME will be inserted
190  * immediately before or immediately after this ME.
191  * \param match_id,match_bits,ignore_bits,unlink,pos,handle See the discussion
192  * for LNetMEAttach().
193  *
194  * \retval 0       On success.
195  * \retval -ENOMEM If new ME object cannot be allocated.
196  * \retval -ENOENT If \a current_meh does not point to a valid match entry.
197  */
198 int
199 LNetMEInsert(lnet_handle_me_t current_meh,
200              lnet_process_id_t match_id,
201              __u64 match_bits, __u64 ignore_bits,
202              lnet_unlink_t unlink, lnet_ins_pos_t pos,
203              lnet_handle_me_t *handle)
204 {
205         lnet_me_t     *current_me;
206         lnet_me_t     *new_me;
207         lnet_portal_t *ptl;
208
209         LASSERT (the_lnet.ln_init);
210         LASSERT (the_lnet.ln_refcount > 0);
211
212         new_me = lnet_me_alloc();
213         if (new_me == NULL)
214                 return -ENOMEM;
215
216         LNET_LOCK();
217
218         current_me = lnet_handle2me(&current_meh);
219         if (current_me == NULL) {
220                 lnet_me_free (new_me);
221
222                 LNET_UNLOCK();
223                 return -ENOENT;
224         }
225
226         LASSERT (current_me->me_portal < the_lnet.ln_nportals);
227
228         ptl = &the_lnet.ln_portals[current_me->me_portal];
229         if (lnet_portal_is_unique(ptl)) {
230                 /* nosense to insertion on unique portal */
231                 lnet_me_free (new_me);
232                 LNET_UNLOCK();
233                 return -EPERM;
234         }
235
236         new_me->me_portal = current_me->me_portal;
237         new_me->me_match_id = match_id;
238         new_me->me_match_bits = match_bits;
239         new_me->me_ignore_bits = ignore_bits;
240         new_me->me_unlink = unlink;
241         new_me->me_md = NULL;
242
243         lnet_initialise_handle (&new_me->me_lh, LNET_COOKIE_TYPE_ME);
244
245         if (pos == LNET_INS_AFTER)
246                 cfs_list_add(&new_me->me_list, &current_me->me_list);
247         else
248                 cfs_list_add_tail(&new_me->me_list, &current_me->me_list);
249
250         lnet_me2handle(handle, new_me);
251
252         LNET_UNLOCK();
253
254         return 0;
255 }
256
257 /**
258  * Unlink a match entry from its match list.
259  *
260  * This operation also releases any resources associated with the ME. If a
261  * memory descriptor is attached to the ME, then it will be unlinked as well
262  * and an unlink event will be generated. It is an error to use the ME handle
263  * after calling LNetMEUnlink().
264  *
265  * \param meh A handle for the ME to be unlinked.
266  *
267  * \retval 0       On success.
268  * \retval -ENOENT If \a meh does not point to a valid ME.
269  * \see LNetMDUnlink() for the discussion on delivering unlink event.
270  */
271 int
272 LNetMEUnlink(lnet_handle_me_t meh)
273 {
274         lnet_me_t    *me;
275         lnet_libmd_t *md;
276         lnet_event_t  ev;
277
278         LASSERT (the_lnet.ln_init);
279         LASSERT (the_lnet.ln_refcount > 0);
280
281         LNET_LOCK();
282
283         me = lnet_handle2me(&meh);
284         if (me == NULL) {
285                 LNET_UNLOCK();
286                 return -ENOENT;
287         }
288
289         md = me->me_md;
290         if (md != NULL &&
291             md->md_eq != NULL &&
292             md->md_refcount == 0) {
293                 lnet_build_unlink_event(md, &ev);
294                 lnet_enq_event_locked(md->md_eq, &ev);
295         }
296
297         lnet_me_unlink(me);
298
299         LNET_UNLOCK();
300         return 0;
301 }
302
303 /* call with LNET_LOCK please */
304 void
305 lnet_me_unlink(lnet_me_t *me)
306 {
307         cfs_list_del (&me->me_list);
308
309         if (me->me_md != NULL) {
310                 me->me_md->md_me = NULL;
311                 lnet_md_unlink(me->me_md);
312         }
313
314         lnet_invalidate_handle (&me->me_lh);
315         lnet_me_free(me);
316 }
317
318 #if 0
319 static void
320 lib_me_dump(lnet_me_t *me)
321 {
322         CWARN("Match Entry %p ("LPX64")\n", me,
323               me->me_lh.lh_cookie);
324
325         CWARN("\tMatch/Ignore\t= %016lx / %016lx\n",
326               me->me_match_bits, me->me_ignore_bits);
327
328         CWARN("\tMD\t= %p\n", me->md);
329         CWARN("\tprev\t= %p\n",
330               cfs_list_entry(me->me_list.prev, lnet_me_t, me_list));
331         CWARN("\tnext\t= %p\n",
332               cfs_list_entry(me->me_list.next, lnet_me_t, me_list));
333 }
334 #endif