1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#define DEBUG_SUBSYSTEM S_LNET
39
40#include <linux/lnet/lib-lnet.h>
41
42
43void
44lnet_md_unlink(struct lnet_libmd *md)
45{
46 if (!(md->md_flags & LNET_MD_FLAG_ZOMBIE)) {
47
48 struct lnet_me *me = md->md_me;
49
50 md->md_flags |= LNET_MD_FLAG_ZOMBIE;
51
52
53
54
55
56
57 if (me) {
58
59 lnet_ptl_detach_md(me, md);
60 if (me->me_unlink == LNET_UNLINK)
61 lnet_me_unlink(me);
62 }
63
64
65 lnet_res_lh_invalidate(&md->md_lh);
66 }
67
68 if (md->md_refcount) {
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) {
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 kfree(md);
85}
86
87static int
88lnet_md_build(struct lnet_libmd *lmd, struct lnet_md *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) {
106 if (umd->options & LNET_MD_KIOV)
107 return -EINVAL;
108
109 niov = umd->length;
110 lmd->md_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
116
117 if (lmd->md_iov.iov[i].iov_len <= 0)
118 return -EINVAL;
119
120 total_length += lmd->md_iov.iov[i].iov_len;
121 }
122
123 lmd->md_length = total_length;
124
125 if ((umd->options & LNET_MD_MAX_SIZE) &&
126 (umd->max_size < 0 ||
127 umd->max_size > total_length))
128 return -EINVAL;
129
130 } else if (umd->options & LNET_MD_KIOV) {
131 niov = umd->length;
132 lmd->md_niov = umd->length;
133 memcpy(lmd->md_iov.kiov, umd->start,
134 niov * sizeof(lmd->md_iov.kiov[0]));
135
136 for (i = 0; i < (int)niov; i++) {
137
138 if (lmd->md_iov.kiov[i].bv_offset +
139 lmd->md_iov.kiov[i].bv_len > PAGE_SIZE)
140 return -EINVAL;
141
142 total_length += lmd->md_iov.kiov[i].bv_len;
143 }
144
145 lmd->md_length = total_length;
146
147 if ((umd->options & LNET_MD_MAX_SIZE) &&
148 (umd->max_size < 0 ||
149 umd->max_size > total_length))
150 return -EINVAL;
151 } else {
152 lmd->md_length = umd->length;
153 niov = 1;
154 lmd->md_niov = 1;
155 lmd->md_iov.iov[0].iov_base = umd->start;
156 lmd->md_iov.iov[0].iov_len = umd->length;
157
158 if ((umd->options & LNET_MD_MAX_SIZE) &&
159 (umd->max_size < 0 ||
160 umd->max_size > (int)umd->length))
161 return -EINVAL;
162 }
163
164 return 0;
165}
166
167
168static int
169lnet_md_link(struct lnet_libmd *md, struct lnet_handle_eq eq_handle, int cpt)
170{
171 struct lnet_res_container *container = the_lnet.ln_md_containers[cpt];
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 if (!LNetEQHandleIsInvalid(eq_handle)) {
190 md->md_eq = lnet_handle2eq(&eq_handle);
191
192 if (!md->md_eq)
193 return -ENOENT;
194
195 (*md->md_eq->eq_refs[cpt])++;
196 }
197
198 lnet_res_lh_initialize(container, &md->md_lh);
199
200 LASSERT(list_empty(&md->md_list));
201 list_add(&md->md_list, &container->rec_active);
202
203 return 0;
204}
205
206
207void
208lnet_md_deconstruct(struct lnet_libmd *lmd, struct lnet_md *umd)
209{
210
211
212
213
214
215 umd->start = lmd->md_start;
216 umd->length = !(lmd->md_options &
217 (LNET_MD_IOVEC | LNET_MD_KIOV)) ?
218 lmd->md_length : lmd->md_niov;
219 umd->threshold = lmd->md_threshold;
220 umd->max_size = lmd->md_max_size;
221 umd->options = lmd->md_options;
222 umd->user_ptr = lmd->md_user_ptr;
223 lnet_eq2handle(&umd->eq_handle, lmd->md_eq);
224}
225
226static int
227lnet_md_validate(struct lnet_md *umd)
228{
229 if (!umd->start && umd->length) {
230 CERROR("MD start pointer can not be NULL with length %u\n",
231 umd->length);
232 return -EINVAL;
233 }
234
235 if ((umd->options & (LNET_MD_KIOV | LNET_MD_IOVEC)) &&
236 umd->length > LNET_MAX_IOV) {
237 CERROR("Invalid option: too many fragments %u, %d max\n",
238 umd->length, LNET_MAX_IOV);
239 return -EINVAL;
240 }
241
242 return 0;
243}
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270int
271LNetMDAttach(struct lnet_handle_me meh, struct lnet_md umd,
272 enum lnet_unlink unlink, struct lnet_handle_md *handle)
273{
274 LIST_HEAD(matches);
275 LIST_HEAD(drops);
276 struct lnet_me *me;
277 struct lnet_libmd *md;
278 int cpt;
279 int rc;
280
281 LASSERT(the_lnet.ln_refcount > 0);
282
283 if (lnet_md_validate(&umd))
284 return -EINVAL;
285
286 if (!(umd.options & (LNET_MD_OP_GET | LNET_MD_OP_PUT))) {
287 CERROR("Invalid option: no MD_OP set\n");
288 return -EINVAL;
289 }
290
291 md = lnet_md_alloc(&umd);
292 if (!md)
293 return -ENOMEM;
294
295 rc = lnet_md_build(md, &umd, unlink);
296 if (rc)
297 goto out_free;
298
299 cpt = lnet_cpt_of_cookie(meh.cookie);
300
301 lnet_res_lock(cpt);
302
303 me = lnet_handle2me(&meh);
304 if (!me)
305 rc = -ENOENT;
306 else if (me->me_md)
307 rc = -EBUSY;
308 else
309 rc = lnet_md_link(md, umd.eq_handle, cpt);
310
311 if (rc)
312 goto out_unlock;
313
314
315
316
317
318 lnet_ptl_attach_md(me, md, &matches, &drops);
319
320 lnet_md2handle(handle, md);
321
322 lnet_res_unlock(cpt);
323
324 lnet_drop_delayed_msg_list(&drops, "Bad match");
325 lnet_recv_delayed_msg_list(&matches);
326
327 return 0;
328
329out_unlock:
330 lnet_res_unlock(cpt);
331out_free:
332 kfree(md);
333 return rc;
334}
335EXPORT_SYMBOL(LNetMDAttach);
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353int
354LNetMDBind(struct lnet_md umd, enum lnet_unlink unlink,
355 struct lnet_handle_md *handle)
356{
357 struct lnet_libmd *md;
358 int cpt;
359 int rc;
360
361 LASSERT(the_lnet.ln_refcount > 0);
362
363 if (lnet_md_validate(&umd))
364 return -EINVAL;
365
366 if ((umd.options & (LNET_MD_OP_GET | LNET_MD_OP_PUT))) {
367 CERROR("Invalid option: GET|PUT illegal on active MDs\n");
368 return -EINVAL;
369 }
370
371 md = lnet_md_alloc(&umd);
372 if (!md)
373 return -ENOMEM;
374
375 rc = lnet_md_build(md, &umd, unlink);
376 if (rc)
377 goto out_free;
378
379 cpt = lnet_res_lock_current();
380
381 rc = lnet_md_link(md, umd.eq_handle, cpt);
382 if (rc)
383 goto out_unlock;
384
385 lnet_md2handle(handle, md);
386
387 lnet_res_unlock(cpt);
388 return 0;
389
390out_unlock:
391 lnet_res_unlock(cpt);
392out_free:
393 kfree(md);
394
395 return rc;
396}
397EXPORT_SYMBOL(LNetMDBind);
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429int
430LNetMDUnlink(struct lnet_handle_md mdh)
431{
432 struct lnet_event ev;
433 struct lnet_libmd *md;
434 int cpt;
435
436 LASSERT(the_lnet.ln_refcount > 0);
437
438 cpt = lnet_cpt_of_cookie(mdh.cookie);
439 lnet_res_lock(cpt);
440
441 md = lnet_handle2md(&mdh);
442 if (!md) {
443 lnet_res_unlock(cpt);
444 return -ENOENT;
445 }
446
447 md->md_flags |= LNET_MD_FLAG_ABORTED;
448
449
450
451
452
453 if (md->md_eq && !md->md_refcount) {
454 lnet_build_unlink_event(md, &ev);
455 lnet_eq_enqueue_event(md->md_eq, &ev);
456 }
457
458 lnet_md_unlink(md);
459
460 lnet_res_unlock(cpt);
461 return 0;
462}
463EXPORT_SYMBOL(LNetMDUnlink);
464