Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[fs/lustre-release.git] / lnet / lnet / lib-md.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
4  * Use is subject to license terms.
5  *
6  * Copyright (c) 2012, 2017, Intel Corporation.
7  */
8
9 /* This file is part of Lustre, http://www.lustre.org/
10  *
11  * Memory Descriptor management routines
12  */
13
14 #define DEBUG_SUBSYSTEM S_LNET
15
16 #include <lnet/lib-lnet.h>
17
18 /* must be called with lnet_res_lock held */
19 void
20 lnet_md_unlink(struct lnet_libmd *md)
21 {
22         if ((md->md_flags & LNET_MD_FLAG_ZOMBIE) == 0) {
23                 /* first unlink attempt... */
24                 struct lnet_me *me = md->md_me;
25
26                 md->md_flags |= LNET_MD_FLAG_ZOMBIE;
27
28                 /* Disassociate from ME (if any), and unlink it if it was created
29                  * with LNET_UNLINK */
30                 if (me != NULL) {
31                         /* detach MD from portal */
32                         lnet_ptl_detach_md(me, md);
33                         if (me->me_unlink == LNET_UNLINK)
34                                 lnet_me_unlink(me);
35                 }
36
37                 /* ensure all future handle lookups fail */
38                 lnet_res_lh_invalidate(&md->md_lh);
39         }
40
41         if (md->md_refcount != 0) {
42                 CDEBUG(D_NET, "Queueing unlink of md %p\n", md);
43                 return;
44         }
45
46         CDEBUG(D_NET, "Unlinking md %p\n", md);
47
48         LASSERT(!list_empty(&md->md_list));
49         list_del_init(&md->md_list);
50         LASSERT(!(md->md_flags & LNET_MD_FLAG_HANDLING));
51         lnet_md_free(md);
52 }
53
54 struct page *
55 lnet_get_first_page(struct lnet_libmd *md, unsigned int offset)
56 {
57         unsigned int niov;
58         struct bio_vec *kiov;
59
60         /*
61          * if the md_options has a bulk handle then we want to look at the
62          * bulk md because that's the data which we will be DMAing
63          */
64         if (md && (md->md_options & LNET_MD_BULK_HANDLE) != 0 &&
65             !LNetMDHandleIsInvalid(md->md_bulk_handle))
66                 md = lnet_handle2md(&md->md_bulk_handle);
67
68         if (!md || md->md_niov == 0)
69                 return NULL;
70
71         kiov = md->md_kiov;
72         niov = md->md_niov;
73
74         while (offset >= kiov->bv_len) {
75                 offset -= kiov->bv_len;
76                 niov--;
77                 kiov++;
78                 if (niov == 0) {
79                         CERROR("offset %d goes beyond kiov\n", offset);
80                         return NULL;
81                 }
82         }
83
84         return kiov->bv_page;
85 }
86
87 int
88 lnet_cpt_of_md(struct lnet_libmd *md, unsigned int offset)
89 {
90         struct page *page;
91         int cpt = CFS_CPT_ANY;
92
93         page = lnet_get_first_page(md, offset);
94         if (!page) {
95                 CDEBUG(D_NET, "Couldn't resolve first page of md %p with offset %u\n",
96                         md, offset);
97                 goto out;
98         }
99
100         cpt = cfs_cpt_of_node(lnet_cpt_table(), page_to_nid(page));
101
102 out:
103         return cpt;
104 }
105
106 static int lnet_md_validate(const struct lnet_md *umd);
107
108 static struct lnet_libmd *
109 lnet_md_build(const struct lnet_md *umd, int unlink)
110 {
111         int i;
112         unsigned int niov;
113         int total_length = 0;
114         struct lnet_libmd *lmd;
115         unsigned int size;
116
117         if (lnet_md_validate(umd) != 0)
118                 return ERR_PTR(-EINVAL);
119
120         if (umd->options & LNET_MD_KIOV)
121                 niov = umd->length;
122         else
123                 niov = DIV_ROUND_UP(offset_in_page(umd->start) + umd->length,
124                                     PAGE_SIZE);
125         size = offsetof(struct lnet_libmd, md_kiov[niov]);
126
127         if (size <= LNET_SMALL_MD_SIZE) {
128                 lmd = kmem_cache_zalloc(lnet_small_mds_cachep, GFP_NOFS);
129                 if (lmd) {
130                         LIBCFS_MEM_MSG(lmd, size, "slab-alloced");
131                 } else {
132                         CDEBUG(D_MALLOC, "failed to allocate 'md' of size %u\n",
133                                size);
134                 }
135         } else {
136                 LIBCFS_ALLOC(lmd, size);
137         }
138
139         if (!lmd)
140                 return ERR_PTR(-ENOMEM);
141
142         lmd->md_niov = niov;
143         INIT_LIST_HEAD(&lmd->md_list);
144         lmd->md_me = NULL;
145         lmd->md_start = umd->start;
146         lmd->md_offset = 0;
147         lmd->md_max_size = umd->max_size;
148         lmd->md_options = umd->options;
149         lmd->md_user_ptr = umd->user_ptr;
150         lmd->md_handler = NULL;
151         lmd->md_threshold = umd->threshold;
152         lmd->md_refcount = 0;
153         lmd->md_flags = (unlink == LNET_UNLINK) ? LNET_MD_FLAG_AUTO_UNLINK : 0;
154         lmd->md_bulk_handle = umd->bulk_handle;
155
156         if (umd->options & LNET_MD_GPU_ADDR)
157                 lmd->md_flags |= LNET_MD_FLAG_GPU;
158
159         if (umd->options & LNET_MD_KIOV) {
160                 memcpy(lmd->md_kiov, umd->start,
161                        niov * sizeof(lmd->md_kiov[0]));
162
163                 for (i = 0; i < (int)niov; i++) {
164                         /* We take the page pointer on trust */
165                         if (lmd->md_kiov[i].bv_offset +
166                             lmd->md_kiov[i].bv_len > PAGE_SIZE) {
167                                 lnet_md_free(lmd);
168                                 return ERR_PTR(-EINVAL); /* invalid length */
169                         }
170
171                         total_length += lmd->md_kiov[i].bv_len;
172                 }
173
174                 lmd->md_length = total_length;
175
176                 if ((umd->options & LNET_MD_MAX_SIZE) && /* max size used */
177                     (umd->max_size < 0 ||
178                      umd->max_size > total_length)) { /* illegal max_size */
179                         lnet_md_free(lmd);
180                         return ERR_PTR(-EINVAL);
181                 }
182         } else {   /* contiguous - split into pages */
183                 void *pa = umd->start;
184                 int len = umd->length;
185
186                 lmd->md_length = len;
187                 i = 0;
188                 while (len) {
189                         struct page *p;
190                         int plen;
191
192                         if (is_vmalloc_addr(pa))
193                                 p = vmalloc_to_page(pa);
194                         else
195                                 p = virt_to_page(pa);
196                         plen = min_t(int, len, PAGE_SIZE - offset_in_page(pa));
197
198                         lmd->md_kiov[i].bv_page = p;
199                         lmd->md_kiov[i].bv_offset = offset_in_page(pa);
200                         lmd->md_kiov[i].bv_len = plen;
201
202                         len -= plen;
203                         pa += plen;
204                         i += 1;
205                 }
206
207                 WARN(!(lmd->md_options  & LNET_MD_GNILND) && i > LNET_MAX_IOV,
208                         "Max IOV exceeded: %d should be < %d\n",
209                         i, LNET_MAX_IOV);
210                 if ((umd->options & LNET_MD_MAX_SIZE) && /* max size used */
211                     (umd->max_size < 0 ||
212                      umd->max_size > (int)umd->length)) { /* illegal max_size */
213                         lnet_md_free(lmd);
214                         return ERR_PTR(-EINVAL);
215                 }
216                 lmd->md_options |= LNET_MD_KIOV;
217         }
218
219         return lmd;
220 }
221
222 /* must be called with resource lock held */
223 static void
224 lnet_md_link(struct lnet_libmd *md, lnet_handler_t handler, int cpt)
225 {
226         struct lnet_res_container *container = the_lnet.ln_md_containers[cpt];
227
228         /* NB we are passed an allocated, but inactive md.
229          * Caller may lnet_md_unlink() it, or may lnet_md_free() it.
230          */
231         /* This implementation doesn't know how to create START events or
232          * disable END events.  Best to LASSERT our caller is compliant so
233          * we find out quickly...  */
234         /*  TODO - reevaluate what should be here in light of
235          * the removal of the start and end events
236          * maybe there we shouldn't even allow LNET_EQ_NONE!)
237          * LASSERT (handler != NULL);
238          */
239         md->md_handler = handler;
240
241         lnet_res_lh_initialize(container, &md->md_lh);
242
243         LASSERT(list_empty(&md->md_list));
244         list_add(&md->md_list, &container->rec_active);
245 }
246
247 bool lnet_assert_handler_unused(lnet_handler_t handler, bool assert)
248 {
249         struct lnet_res_container *container;
250         int cpt;
251         bool handler_in_use = false;
252
253         if (!handler)
254                 return handler_in_use;
255         cfs_percpt_for_each(container, cpt, the_lnet.ln_md_containers) {
256                 struct lnet_libmd *md;
257
258                 lnet_res_lock(cpt);
259                 list_for_each_entry(md, &container->rec_active, md_list) {
260                         if (assert) {
261                                 LASSERT(md->md_handler != handler);
262                         } else if (md->md_handler == handler) {
263                                 handler_in_use = true;
264                                 break;
265                         }
266                 }
267                 lnet_res_unlock(cpt);
268         }
269         return handler_in_use;
270 }
271 EXPORT_SYMBOL(lnet_assert_handler_unused);
272
273 /* must be called with lnet_res_lock held */
274 void
275 lnet_md_deconstruct(struct lnet_libmd *lmd, struct lnet_event *ev)
276 {
277         ev->md_start = lmd->md_start;
278         ev->md_options = lmd->md_options;
279         ev->md_user_ptr = lmd->md_user_ptr;
280 }
281
282 static int
283 lnet_md_validate(const struct lnet_md *umd)
284 {
285         if (umd->start == NULL && umd->length != 0) {
286                 CERROR("MD start pointer can not be NULL with length %u\n",
287                        umd->length);
288                 return -EINVAL;
289         }
290
291         if ((umd->options & LNET_MD_KIOV) &&
292             umd->length > LNET_MAX_IOV) {
293                 CERROR("Invalid option: too many fragments %u, %d max\n",
294                        umd->length, LNET_MAX_IOV);
295                 return -EINVAL;
296         }
297
298         return 0;
299 }
300
301 /**
302  * Create a memory descriptor and attach it to a ME
303  *
304  * \param me An ME to associate the new MD with.
305  * \param umd Provides initial values for the user-visible parts of a MD.
306  * Other than its use for initialization, there is no linkage between this
307  * structure and the MD maintained by the LNet.
308  * \param unlink A flag to indicate whether the MD is automatically unlinked
309  * when it becomes inactive, either because the operation threshold drops to
310  * zero or because the available memory becomes less than \a umd.max_size.
311  * (Note that the check for unlinking a MD only occurs after the completion
312  * of a successful operation on the MD.) The value LNET_UNLINK enables auto
313  * unlinking; the value LNET_RETAIN disables it.
314  * \param handle On successful returns, a handle to the newly created MD is
315  * saved here. This handle can be used later in LNetMDUnlink().
316  *
317  * The ME will either be linked to the new MD, or it will be freed.
318  *
319  * \retval 0       On success.
320  * \retval -EINVAL If \a umd is not valid.
321  * \retval -ENOMEM If new MD cannot be allocated.
322  */
323 int
324 LNetMDAttach(struct lnet_me *me, const struct lnet_md *umd,
325              enum lnet_unlink unlink, struct lnet_handle_md *handle)
326 {
327         LIST_HEAD(matches);
328         LIST_HEAD(drops);
329         struct lnet_libmd       *md;
330         int                     cpt;
331
332         LASSERT(the_lnet.ln_refcount > 0);
333         LASSERT(!me->me_md);
334
335         if ((umd->options & (LNET_MD_OP_GET | LNET_MD_OP_PUT)) == 0) {
336                 CERROR("Invalid option: no MD_OP set\n");
337                 md = ERR_PTR(-EINVAL);
338         } else
339                 md = lnet_md_build(umd, unlink);
340
341         cpt = me->me_cpt;
342         lnet_res_lock(cpt);
343
344         if (IS_ERR(md)) {
345                 lnet_me_unlink(me);
346                 lnet_res_unlock(cpt);
347                 return PTR_ERR(md);
348         }
349
350         lnet_md_link(md, umd->handler, cpt);
351
352         /* attach this MD to portal of ME and check if it matches any
353          * blocked msgs on this portal */
354         lnet_ptl_attach_md(me, md, &matches, &drops);
355
356         lnet_md2handle(handle, md);
357
358         lnet_res_unlock(cpt);
359
360         lnet_drop_delayed_msg_list(&drops, "Bad match");
361         lnet_recv_delayed_msg_list(&matches);
362
363         return 0;
364 }
365 EXPORT_SYMBOL(LNetMDAttach);
366
367 /**
368  * Create a "free floating" memory descriptor - a MD that is not associated
369  * with a ME. Such MDs are usually used in LNetPut() and LNetGet() operations.
370  *
371  * \param umd,unlink See the discussion for LNetMDAttach().
372  * \param handle On successful returns, a handle to the newly created MD is
373  * saved here. This handle can be used later in LNetMDUnlink(), LNetPut(),
374  * and LNetGet() operations.
375  *
376  * \retval 0       On success.
377  * \retval -EINVAL If \a umd is not valid.
378  * \retval -ENOMEM If new MD cannot be allocated.
379  */
380 int
381 LNetMDBind(const struct lnet_md *umd, enum lnet_unlink unlink,
382            struct lnet_handle_md *handle)
383 {
384         struct lnet_libmd       *md;
385         int             cpt;
386         int             rc;
387
388         LASSERT(the_lnet.ln_refcount > 0);
389
390         if ((umd->options & (LNET_MD_OP_GET | LNET_MD_OP_PUT)) != 0) {
391                 CERROR("Invalid option: GET|PUT illegal on active MDs\n");
392                 return -EINVAL;
393         }
394
395         md = lnet_md_build(umd, unlink);
396         if (IS_ERR(md))
397                 return PTR_ERR(md);
398
399         if (md->md_length > LNET_MTU) {
400                 CERROR("Invalid length: too big transfer size %u, %d max\n",
401                        md->md_length, LNET_MTU);
402                 rc = -EINVAL;
403                 goto out_free;
404         }
405
406         cpt = lnet_res_lock_current();
407
408         lnet_md_link(md, umd->handler, cpt);
409
410         lnet_md2handle(handle, md);
411
412         lnet_res_unlock(cpt);
413         return 0;
414
415  out_free:
416         lnet_md_free(md);
417         return rc;
418 }
419 EXPORT_SYMBOL(LNetMDBind);
420
421 /**
422  * Unlink the memory descriptor from any ME it may be linked to and release
423  * the internal resources associated with it. As a result, active messages
424  * associated with the MD may get aborted.
425  *
426  * This function does not free the memory region associated with the MD;
427  * i.e., the memory the user allocated for this MD. If the ME associated with
428  * this MD is not NULL and was created with auto unlink enabled, the ME is
429  * unlinked as well (see LNetMEAttach()).
430  *
431  * Explicitly unlinking a MD via this function call has the same behavior as
432  * a MD that has been automatically unlinked, except that no LNET_EVENT_UNLINK
433  * is generated in the latter case.
434  *
435  * An unlinked event can be reported in two ways:
436  * - If there's no pending operations on the MD, it's unlinked immediately
437  *   and an LNET_EVENT_UNLINK event is logged before this function returns.
438  * - Otherwise, the MD is only marked for deletion when this function
439  *   returns, and the unlinked event will be piggybacked on the event of
440  *   the completion of the last operation by setting the unlinked field of
441  *   the event. No dedicated LNET_EVENT_UNLINK event is generated.
442  *
443  * Note that in both cases the unlinked field of the event is always set; no
444  * more event will happen on the MD after such an event is logged.
445  *
446  * \param mdh A handle for the MD to be unlinked.
447  *
448  * \retval 0       On success.
449  * \retval -ENOENT If \a mdh does not point to a valid MD object.
450  */
451 int
452 __LNetMDUnlink(struct lnet_handle_md mdh, bool discard)
453 {
454         struct lnet_event ev;
455         struct lnet_libmd *md = NULL;
456         lnet_handler_t handler = NULL;
457         int cpt;
458
459         LASSERT(the_lnet.ln_refcount > 0);
460
461         cpt = lnet_cpt_of_cookie(mdh.cookie);
462         lnet_res_lock(cpt);
463         while (!md) {
464                 md = lnet_handle2md(&mdh);
465                 if (!md) {
466                         lnet_res_unlock(cpt);
467                         return -ENOENT;
468                 }
469                 if (md->md_refcount == 0 &&
470                     md->md_flags & LNET_MD_FLAG_HANDLING) {
471                         /* Race with unlocked call to ->md_handler. */
472                         lnet_md_wait_handling(md, cpt);
473                         md = NULL;
474                 }
475         }
476
477         md->md_flags |= LNET_MD_FLAG_ABORTED;
478         /* If the MD is busy, lnet_md_unlink just marks it for deletion, and
479          * when the LND is done, the completion event flags that the MD was
480          * unlinked. Otherwise, we enqueue an event now... */
481         if (md->md_handler && md->md_refcount == 0) {
482                 lnet_build_unlink_event(md, &ev);
483                 handler = md->md_handler;
484         }
485
486         if (discard)
487                 md->md_flags |= LNET_MD_FLAG_DISCARD;
488
489         if (md->md_rspt_ptr != NULL)
490                 lnet_detach_rsp_tracker(md, cpt);
491
492         lnet_md_unlink(md);
493
494         lnet_res_unlock(cpt);
495
496         if (handler)
497                 handler(&ev);
498
499         return 0;
500 }
501 EXPORT_SYMBOL(__LNetMDUnlink);
502
503 bool
504 lnet_md_discarded(struct lnet_libmd *md)
505 {
506         bool rc;
507         int cpt;
508
509         if (md == NULL)
510                 return false;
511
512         cpt = lnet_cpt_of_cookie(md->md_lh.lh_cookie);
513         lnet_res_lock(cpt);
514         rc = md->md_flags & LNET_MD_FLAG_DISCARD;
515         lnet_res_unlock(cpt);
516
517         return rc;
518 }
519 EXPORT_SYMBOL(lnet_md_discarded);