Whamcloud - gitweb
LU-3963 libcfs: remove proc handler wrappers
[fs/lustre-release.git] / lnet / lnet / lib-md.c
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-md.c
37  *
38  * Memory Descriptor management routines
39  */
40
41 #define DEBUG_SUBSYSTEM S_LNET
42
43 #include <lnet/lib-lnet.h>
44
45 /* must be called with lnet_res_lock held */
46 void
47 lnet_md_unlink(lnet_libmd_t *md)
48 {
49         if ((md->md_flags & LNET_MD_FLAG_ZOMBIE) == 0) {
50                 /* first unlink attempt... */
51                 lnet_me_t *me = md->md_me;
52
53                 md->md_flags |= LNET_MD_FLAG_ZOMBIE;
54
55                 /* Disassociate from ME (if any), and unlink it if it was created
56                  * with LNET_UNLINK */
57                 if (me != NULL) {
58                         /* detach MD from portal */
59                         lnet_ptl_detach_md(me, md);
60                         if (me->me_unlink == LNET_UNLINK)
61                                 lnet_me_unlink(me);
62                 }
63
64                 /* ensure all future handle lookups fail */
65                 lnet_res_lh_invalidate(&md->md_lh);
66         }
67
68         if (md->md_refcount != 0) {
69                 CDEBUG(D_NET, "Queueing unlink of md %p\n", md);
70                 return;
71         }
72
73         CDEBUG(D_NET, "Unlinking md %p\n", md);
74
75         if (md->md_eq != NULL) {
76                 int     cpt = lnet_cpt_of_cookie(md->md_lh.lh_cookie);
77
78                 LASSERT(*md->md_eq->eq_refs[cpt] > 0);
79                 (*md->md_eq->eq_refs[cpt])--;
80         }
81
82         LASSERT(!list_empty(&md->md_list));
83         list_del_init(&md->md_list);
84         lnet_md_free_locked(md);
85 }
86
87 static int
88 lnet_md_build(lnet_libmd_t *lmd, lnet_md_t *umd, int unlink)
89 {
90         int          i;
91         unsigned int niov;
92         int          total_length = 0;
93
94         lmd->md_me = NULL;
95         lmd->md_start = umd->start;
96         lmd->md_offset = 0;
97         lmd->md_max_size = umd->max_size;
98         lmd->md_options = umd->options;
99         lmd->md_user_ptr = umd->user_ptr;
100         lmd->md_eq = NULL;
101         lmd->md_threshold = umd->threshold;
102         lmd->md_refcount = 0;
103         lmd->md_flags = (unlink == LNET_UNLINK) ? LNET_MD_FLAG_AUTO_UNLINK : 0;
104
105         if ((umd->options & LNET_MD_IOVEC) != 0) {
106
107                 if ((umd->options & LNET_MD_KIOV) != 0) /* Can't specify both */
108                         return -EINVAL;
109
110                 lmd->md_niov = niov = umd->length;
111                 memcpy(lmd->md_iov.iov, umd->start,
112                        niov * sizeof (lmd->md_iov.iov[0]));
113
114                 for (i = 0; i < (int)niov; i++) {
115                         /* We take the base address on trust */
116                         if (lmd->md_iov.iov[i].iov_len <= 0) /* invalid length */
117                                 return -EINVAL;
118
119                         total_length += lmd->md_iov.iov[i].iov_len;
120                 }
121
122                 lmd->md_length = total_length;
123
124                 if ((umd->options & LNET_MD_MAX_SIZE) != 0 && /* max size used */
125                     (umd->max_size < 0 ||
126                      umd->max_size > total_length)) // illegal max_size
127                         return -EINVAL;
128
129         } else if ((umd->options & LNET_MD_KIOV) != 0) {
130 #ifndef __KERNEL__
131                 return -EINVAL;
132 #else
133                 lmd->md_niov = niov = umd->length;
134                 memcpy(lmd->md_iov.kiov, umd->start,
135                        niov * sizeof (lmd->md_iov.kiov[0]));
136
137                 for (i = 0; i < (int)niov; i++) {
138                         /* We take the page pointer on trust */
139                         if (lmd->md_iov.kiov[i].kiov_offset +
140                             lmd->md_iov.kiov[i].kiov_len > PAGE_CACHE_SIZE)
141                                 return -EINVAL; /* invalid length */
142
143                         total_length += lmd->md_iov.kiov[i].kiov_len;
144                 }
145
146                 lmd->md_length = total_length;
147
148                 if ((umd->options & LNET_MD_MAX_SIZE) != 0 && /* max size used */
149                     (umd->max_size < 0 ||
150                      umd->max_size > total_length)) // illegal max_size
151                         return -EINVAL;
152 #endif
153         } else {   /* contiguous */
154                 lmd->md_length = umd->length;
155                 lmd->md_niov = niov = 1;
156                 lmd->md_iov.iov[0].iov_base = umd->start;
157                 lmd->md_iov.iov[0].iov_len = umd->length;
158
159                 if ((umd->options & LNET_MD_MAX_SIZE) != 0 && /* max size used */
160                     (umd->max_size < 0 ||
161                      umd->max_size > (int)umd->length)) // illegal max_size
162                         return -EINVAL;
163         }
164
165         return 0;
166 }
167
168 /* must be called with resource lock held */
169 static int
170 lnet_md_link(lnet_libmd_t *md, lnet_handle_eq_t eq_handle, int cpt)
171 {
172         struct lnet_res_container *container = the_lnet.ln_md_containers[cpt];
173
174         /* NB we are passed an allocated, but inactive md.
175          * if we return success, caller may lnet_md_unlink() it.
176          * otherwise caller may only lnet_md_free() it.
177          */
178         /* This implementation doesn't know how to create START events or
179          * disable END events.  Best to LASSERT our caller is compliant so
180          * we find out quickly...  */
181         /*  TODO - reevaluate what should be here in light of
182          * the removal of the start and end events
183          * maybe there we shouldn't even allow LNET_EQ_NONE!)
184          * LASSERT (eq == NULL);
185          */
186         if (!LNetHandleIsInvalid(eq_handle)) {
187                 md->md_eq = lnet_handle2eq(&eq_handle);
188
189                 if (md->md_eq == NULL)
190                         return -ENOENT;
191
192                 (*md->md_eq->eq_refs[cpt])++;
193         }
194
195         lnet_res_lh_initialize(container, &md->md_lh);
196
197         LASSERT(list_empty(&md->md_list));
198         list_add(&md->md_list, &container->rec_active);
199
200         return 0;
201 }
202
203 /* must be called with lnet_res_lock held */
204 void
205 lnet_md_deconstruct(lnet_libmd_t *lmd, lnet_md_t *umd)
206 {
207         /* NB this doesn't copy out all the iov entries so when a
208          * discontiguous MD is copied out, the target gets to know the
209          * original iov pointer (in start) and the number of entries it had
210          * and that's all.
211          */
212         umd->start = lmd->md_start;
213         umd->length = ((lmd->md_options & (LNET_MD_IOVEC | LNET_MD_KIOV)) == 0) ?
214                       lmd->md_length : lmd->md_niov;
215         umd->threshold = lmd->md_threshold;
216         umd->max_size = lmd->md_max_size;
217         umd->options = lmd->md_options;
218         umd->user_ptr = lmd->md_user_ptr;
219         lnet_eq2handle(&umd->eq_handle, lmd->md_eq);
220 }
221
222 int
223 lnet_md_validate(lnet_md_t *umd)
224 {
225         if (umd->start == NULL && umd->length != 0) {
226                 CERROR("MD start pointer can not be NULL with length %u\n",
227                        umd->length);
228                 return -EINVAL;
229         }
230
231         if ((umd->options & (LNET_MD_KIOV | LNET_MD_IOVEC)) != 0 &&
232             umd->length > LNET_MAX_IOV) {
233                 CERROR("Invalid option: too many fragments %u, %d max\n",
234                        umd->length, LNET_MAX_IOV);
235                 return -EINVAL;
236         }
237
238         return 0;
239 }
240
241 /**
242  * Create a memory descriptor and attach it to a ME
243  *
244  * \param meh A handle for a ME to associate the new MD with.
245  * \param umd Provides initial values for the user-visible parts of a MD.
246  * Other than its use for initialization, there is no linkage between this
247  * structure and the MD maintained by the LNet.
248  * \param unlink A flag to indicate whether the MD is automatically unlinked
249  * when it becomes inactive, either because the operation threshold drops to
250  * zero or because the available memory becomes less than \a umd.max_size.
251  * (Note that the check for unlinking a MD only occurs after the completion
252  * of a successful operation on the MD.) The value LNET_UNLINK enables auto
253  * unlinking; the value LNET_RETAIN disables it.
254  * \param handle On successful returns, a handle to the newly created MD is
255  * saved here. This handle can be used later in LNetMDUnlink().
256  *
257  * \retval 0       On success.
258  * \retval -EINVAL If \a umd is not valid.
259  * \retval -ENOMEM If new MD cannot be allocated.
260  * \retval -ENOENT Either \a meh or \a umd.eq_handle does not point to a
261  * valid object. Note that it's OK to supply a NULL \a umd.eq_handle by
262  * calling LNetInvalidateHandle() on it.
263  * \retval -EBUSY  If the ME pointed to by \a meh is already associated with
264  * a MD.
265  */
266 int
267 LNetMDAttach(lnet_handle_me_t meh, lnet_md_t umd,
268              lnet_unlink_t unlink, lnet_handle_md_t *handle)
269 {
270         struct list_head        matches = LIST_HEAD_INIT(matches);
271         struct list_head        drops = LIST_HEAD_INIT(drops);
272         struct lnet_me          *me;
273         struct lnet_libmd       *md;
274         int                     cpt;
275         int                     rc;
276
277         LASSERT (the_lnet.ln_init);
278         LASSERT (the_lnet.ln_refcount > 0);
279
280         if (lnet_md_validate(&umd) != 0)
281                 return -EINVAL;
282
283         if ((umd.options & (LNET_MD_OP_GET | LNET_MD_OP_PUT)) == 0) {
284                 CERROR("Invalid option: no MD_OP set\n");
285                 return -EINVAL;
286         }
287
288         md = lnet_md_alloc(&umd);
289         if (md == NULL)
290                 return -ENOMEM;
291
292         rc = lnet_md_build(md, &umd, unlink);
293         cpt = lnet_cpt_of_cookie(meh.cookie);
294
295         lnet_res_lock(cpt);
296         if (rc != 0)
297                 goto failed;
298
299         me = lnet_handle2me(&meh);
300         if (me == NULL)
301                 rc = -ENOENT;
302         else if (me->me_md != NULL)
303                 rc = -EBUSY;
304         else
305                 rc = lnet_md_link(md, umd.eq_handle, cpt);
306
307         if (rc != 0)
308                 goto failed;
309
310         /* attach this MD to portal of ME and check if it matches any
311          * blocked msgs on this portal */
312         lnet_ptl_attach_md(me, md, &matches, &drops);
313
314         lnet_md2handle(handle, md);
315
316         lnet_res_unlock(cpt);
317
318         lnet_drop_delayed_msg_list(&drops, "Bad match");
319         lnet_recv_delayed_msg_list(&matches);
320
321         return 0;
322
323  failed:
324         lnet_md_free_locked(md);
325
326         lnet_res_unlock(cpt);
327         return rc;
328 }
329 EXPORT_SYMBOL(LNetMDAttach);
330
331 /**
332  * Create a "free floating" memory descriptor - a MD that is not associated
333  * with a ME. Such MDs are usually used in LNetPut() and LNetGet() operations.
334  *
335  * \param umd,unlink See the discussion for LNetMDAttach().
336  * \param handle On successful returns, a handle to the newly created MD is
337  * saved here. This handle can be used later in LNetMDUnlink(), LNetPut(),
338  * and LNetGet() operations.
339  *
340  * \retval 0       On success.
341  * \retval -EINVAL If \a umd is not valid.
342  * \retval -ENOMEM If new MD cannot be allocated.
343  * \retval -ENOENT \a umd.eq_handle does not point to a valid EQ. Note that
344  * it's OK to supply a NULL \a umd.eq_handle by calling
345  * LNetInvalidateHandle() on it.
346  */
347 int
348 LNetMDBind(lnet_md_t umd, lnet_unlink_t unlink, lnet_handle_md_t *handle)
349 {
350         lnet_libmd_t    *md;
351         int             cpt;
352         int             rc;
353
354         LASSERT (the_lnet.ln_init);
355         LASSERT (the_lnet.ln_refcount > 0);
356
357         if (lnet_md_validate(&umd) != 0)
358                 return -EINVAL;
359
360         if ((umd.options & (LNET_MD_OP_GET | LNET_MD_OP_PUT)) != 0) {
361                 CERROR("Invalid option: GET|PUT illegal on active MDs\n");
362                 return -EINVAL;
363         }
364
365         md = lnet_md_alloc(&umd);
366         if (md == NULL)
367                 return -ENOMEM;
368
369         rc = lnet_md_build(md, &umd, unlink);
370
371         cpt = lnet_res_lock_current();
372         if (rc != 0)
373                 goto failed;
374
375         rc = lnet_md_link(md, umd.eq_handle, cpt);
376         if (rc != 0)
377                 goto failed;
378
379         lnet_md2handle(handle, md);
380
381         lnet_res_unlock(cpt);
382         return 0;
383
384  failed:
385         lnet_md_free_locked(md);
386
387         lnet_res_unlock(cpt);
388         return rc;
389 }
390 EXPORT_SYMBOL(LNetMDBind);
391
392 /**
393  * Unlink the memory descriptor from any ME it may be linked to and release
394  * the internal resources associated with it. As a result, active messages
395  * associated with the MD may get aborted.
396  *
397  * This function does not free the memory region associated with the MD;
398  * i.e., the memory the user allocated for this MD. If the ME associated with
399  * this MD is not NULL and was created with auto unlink enabled, the ME is
400  * unlinked as well (see LNetMEAttach()).
401  *
402  * Explicitly unlinking a MD via this function call has the same behavior as
403  * a MD that has been automatically unlinked, except that no LNET_EVENT_UNLINK
404  * is generated in the latter case.
405  *
406  * An unlinked event can be reported in two ways:
407  * - If there's no pending operations on the MD, it's unlinked immediately
408  *   and an LNET_EVENT_UNLINK event is logged before this function returns.
409  * - Otherwise, the MD is only marked for deletion when this function
410  *   returns, and the unlinked event will be piggybacked on the event of
411  *   the completion of the last operation by setting the unlinked field of
412  *   the event. No dedicated LNET_EVENT_UNLINK event is generated.
413  *
414  * Note that in both cases the unlinked field of the event is always set; no
415  * more event will happen on the MD after such an event is logged.
416  *
417  * \param mdh A handle for the MD to be unlinked.
418  *
419  * \retval 0       On success.
420  * \retval -ENOENT If \a mdh does not point to a valid MD object.
421  */
422 int
423 LNetMDUnlink (lnet_handle_md_t mdh)
424 {
425         lnet_event_t    ev;
426         lnet_libmd_t    *md;
427         int             cpt;
428
429         LASSERT(the_lnet.ln_init);
430         LASSERT(the_lnet.ln_refcount > 0);
431
432         cpt = lnet_cpt_of_cookie(mdh.cookie);
433         lnet_res_lock(cpt);
434
435         md = lnet_handle2md(&mdh);
436         if (md == NULL) {
437                 lnet_res_unlock(cpt);
438                 return -ENOENT;
439         }
440
441         md->md_flags |= LNET_MD_FLAG_ABORTED;
442         /* If the MD is busy, lnet_md_unlink just marks it for deletion, and
443          * when the LND is done, the completion event flags that the MD was
444          * unlinked. Otherwise, we enqueue an event now... */
445         if (md->md_eq != NULL && md->md_refcount == 0) {
446                 lnet_build_unlink_event(md, &ev);
447                 lnet_eq_enqueue_event(md->md_eq, &ev);
448         }
449
450         lnet_md_unlink(md);
451
452         lnet_res_unlock(cpt);
453         return 0;
454 }
455 EXPORT_SYMBOL(LNetMDUnlink);