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