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#define DEBUG_SUBSYSTEM S_LNET
38
39#include <linux/lnet/lib-lnet.h>
40
41
42void
43lnet_md_unlink(struct lnet_libmd *md)
44{
45 if (!(md->md_flags & LNET_MD_FLAG_ZOMBIE)) {
46
47 struct lnet_me *me = md->md_me;
48
49 md->md_flags |= LNET_MD_FLAG_ZOMBIE;
50
51
52
53
54
55
56 if (me) {
57
58 lnet_ptl_detach_md(me, md);
59 if (me->me_unlink == LNET_UNLINK)
60 lnet_me_unlink(me);
61 }
62
63
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
86static int
87lnet_md_build(struct lnet_libmd *lmd, struct lnet_md *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)
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
115
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) &&
125 (umd->max_size < 0 ||
126 umd->max_size > total_length))
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
137 if (lmd->md_iov.kiov[i].bv_offset +
138 lmd->md_iov.kiov[i].bv_len > PAGE_SIZE)
139 return -EINVAL;
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) &&
147 (umd->max_size < 0 ||
148 umd->max_size > total_length))
149 return -EINVAL;
150 } else {
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) &&
158 (umd->max_size < 0 ||
159 umd->max_size > (int)umd->length))
160 return -EINVAL;
161 }
162
163 return 0;
164}
165
166
167static int
168lnet_md_link(struct lnet_libmd *md, struct lnet_handle_eq eq_handle, int cpt)
169{
170 struct lnet_res_container *container = the_lnet.ln_md_containers[cpt];
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188 if (!LNetEQHandleIsInvalid(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
206void
207lnet_md_deconstruct(struct lnet_libmd *lmd, struct lnet_md *umd)
208{
209
210
211
212
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
225static int
226lnet_md_validate(struct lnet_md *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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269int
270LNetMDAttach(struct lnet_handle_me meh, struct lnet_md umd,
271 enum lnet_unlink unlink, struct lnet_handle_md *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
315
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
328out_unlock:
329 lnet_res_unlock(cpt);
330out_free:
331 lnet_md_free(md);
332 return rc;
333}
334EXPORT_SYMBOL(LNetMDAttach);
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352int
353LNetMDBind(struct lnet_md umd, enum lnet_unlink unlink,
354 struct lnet_handle_md *handle)
355{
356 struct lnet_libmd *md;
357 int cpt;
358 int rc;
359
360 LASSERT(the_lnet.ln_refcount > 0);
361
362 if (lnet_md_validate(&umd))
363 return -EINVAL;
364
365 if ((umd.options & (LNET_MD_OP_GET | LNET_MD_OP_PUT))) {
366 CERROR("Invalid option: GET|PUT illegal on active MDs\n");
367 return -EINVAL;
368 }
369
370 md = lnet_md_alloc(&umd);
371 if (!md)
372 return -ENOMEM;
373
374 rc = lnet_md_build(md, &umd, unlink);
375 if (rc)
376 goto out_free;
377
378 cpt = lnet_res_lock_current();
379
380 rc = lnet_md_link(md, umd.eq_handle, cpt);
381 if (rc)
382 goto out_unlock;
383
384 lnet_md2handle(handle, md);
385
386 lnet_res_unlock(cpt);
387 return 0;
388
389out_unlock:
390 lnet_res_unlock(cpt);
391out_free:
392 lnet_md_free(md);
393
394 return rc;
395}
396EXPORT_SYMBOL(LNetMDBind);
397
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
428int
429LNetMDUnlink(struct lnet_handle_md mdh)
430{
431 struct lnet_event ev;
432 struct lnet_libmd *md;
433 int cpt;
434
435 LASSERT(the_lnet.ln_refcount > 0);
436
437 cpt = lnet_cpt_of_cookie(mdh.cookie);
438 lnet_res_lock(cpt);
439
440 md = lnet_handle2md(&mdh);
441 if (!md) {
442 lnet_res_unlock(cpt);
443 return -ENOENT;
444 }
445
446 md->md_flags |= LNET_MD_FLAG_ABORTED;
447
448
449
450
451
452 if (md->md_eq && !md->md_refcount) {
453 lnet_build_unlink_event(md, &ev);
454 lnet_eq_enqueue_event(md->md_eq, &ev);
455 }
456
457 lnet_md_unlink(md);
458
459 lnet_res_unlock(cpt);
460 return 0;
461}
462EXPORT_SYMBOL(LNetMDUnlink);
463