Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2021 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2020, 2021 Mellanox Technologies LTD. All rights reserved.
4 : : */
5 : :
6 : : #include <rdma/rdma_cma.h>
7 : :
8 : : #include "spdk/log.h"
9 : : #include "spdk/env.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/likely.h"
12 : :
13 : : #include "spdk_internal/rdma.h"
14 : : #include "spdk_internal/assert.h"
15 : :
16 : : struct spdk_rdma_device {
17 : : struct ibv_pd *pd;
18 : : struct ibv_context *context;
19 : : int ref;
20 : : bool removed;
21 : : TAILQ_ENTRY(spdk_rdma_device) tailq;
22 : : };
23 : :
24 : : struct spdk_rdma_mem_map {
25 : : struct spdk_mem_map *map;
26 : : struct ibv_pd *pd;
27 : : struct spdk_nvme_rdma_hooks *hooks;
28 : : uint32_t ref_count;
29 : : enum spdk_rdma_memory_map_role role;
30 : : LIST_ENTRY(spdk_rdma_mem_map) link;
31 : : };
32 : :
33 : : static pthread_mutex_t g_dev_mutex = PTHREAD_MUTEX_INITIALIZER;
34 : : static struct ibv_context **g_ctx_list = NULL;
35 : : static TAILQ_HEAD(, spdk_rdma_device) g_dev_list = TAILQ_HEAD_INITIALIZER(g_dev_list);
36 : :
37 : : static LIST_HEAD(, spdk_rdma_mem_map) g_rdma_mr_maps = LIST_HEAD_INITIALIZER(&g_rdma_mr_maps);
38 : : static pthread_mutex_t g_rdma_mr_maps_mutex = PTHREAD_MUTEX_INITIALIZER;
39 : :
40 : : static int
41 : 5456 : rdma_mem_notify(void *cb_ctx, struct spdk_mem_map *map,
42 : : enum spdk_mem_map_notify_action action,
43 : : void *vaddr, size_t size)
44 : : {
45 : 5456 : struct spdk_rdma_mem_map *rmap = cb_ctx;
46 : 5456 : struct ibv_pd *pd = rmap->pd;
47 : : struct ibv_mr *mr;
48 : 5456 : uint32_t access_flags = 0;
49 : : int rc;
50 : :
51 [ + + - ]: 5456 : switch (action) {
52 : 2728 : case SPDK_MEM_MAP_NOTIFY_REGISTER:
53 [ + - - + ]: 2728 : if (rmap->hooks && rmap->hooks->get_rkey) {
54 : 0 : rc = spdk_mem_map_set_translation(map, (uint64_t)vaddr, size, rmap->hooks->get_rkey(pd, vaddr,
55 : : size));
56 : : } else {
57 [ + + - ]: 2728 : switch (rmap->role) {
58 : 2178 : case SPDK_RDMA_MEMORY_MAP_ROLE_TARGET:
59 : 2178 : access_flags = IBV_ACCESS_LOCAL_WRITE;
60 [ - + ]: 2178 : if (pd->context->device->transport_type == IBV_TRANSPORT_IWARP) {
61 : : /* IWARP requires REMOTE_WRITE permission for RDMA_READ operation */
62 : 0 : access_flags |= IBV_ACCESS_REMOTE_WRITE;
63 : : }
64 : 2178 : break;
65 : 550 : case SPDK_RDMA_MEMORY_MAP_ROLE_INITIATOR:
66 : 550 : access_flags = IBV_ACCESS_LOCAL_WRITE | IBV_ACCESS_REMOTE_READ | IBV_ACCESS_REMOTE_WRITE;
67 : 550 : break;
68 : 0 : default:
69 : 0 : SPDK_UNREACHABLE();
70 : : }
71 : : #ifdef IBV_ACCESS_OPTIONAL_FIRST
72 [ - + ]: 2728 : access_flags |= IBV_ACCESS_RELAXED_ORDERING;
73 : : #endif
74 : 2728 : mr = ibv_reg_mr(pd, vaddr, size, access_flags);
75 [ - + ]: 2728 : if (mr == NULL) {
76 : 0 : SPDK_ERRLOG("ibv_reg_mr() failed\n");
77 : 0 : return -1;
78 : : } else {
79 : 2728 : rc = spdk_mem_map_set_translation(map, (uint64_t)vaddr, size, (uint64_t)mr);
80 : : }
81 : : }
82 : 2728 : break;
83 : 2728 : case SPDK_MEM_MAP_NOTIFY_UNREGISTER:
84 [ + - + - ]: 2728 : if (rmap->hooks == NULL || rmap->hooks->get_rkey == NULL) {
85 : 2728 : mr = (struct ibv_mr *)spdk_mem_map_translate(map, (uint64_t)vaddr, NULL);
86 [ + - ]: 2728 : if (mr) {
87 : 2728 : ibv_dereg_mr(mr);
88 : : }
89 : : }
90 : 2728 : rc = spdk_mem_map_clear_translation(map, (uint64_t)vaddr, size);
91 : 2728 : break;
92 : 0 : default:
93 : 0 : SPDK_UNREACHABLE();
94 : : }
95 : :
96 : 5456 : return rc;
97 : : }
98 : :
99 : : static int
100 : 338 : rdma_check_contiguous_entries(uint64_t addr_1, uint64_t addr_2)
101 : : {
102 : : /* Two contiguous mappings will point to the same address which is the start of the RDMA MR. */
103 : 338 : return addr_1 == addr_2;
104 : : }
105 : :
106 : : const struct spdk_mem_map_ops g_rdma_map_ops = {
107 : : .notify_cb = rdma_mem_notify,
108 : : .are_contiguous = rdma_check_contiguous_entries
109 : : };
110 : :
111 : : static void
112 : 232 : _rdma_free_mem_map(struct spdk_rdma_mem_map *map)
113 : : {
114 [ - + ]: 232 : assert(map);
115 : :
116 [ + - ]: 232 : if (map->hooks) {
117 : 232 : spdk_free(map);
118 : : } else {
119 : 0 : free(map);
120 : : }
121 : 232 : }
122 : :
123 : : struct spdk_rdma_mem_map *
124 : 1019 : spdk_rdma_create_mem_map(struct ibv_pd *pd, struct spdk_nvme_rdma_hooks *hooks,
125 : : enum spdk_rdma_memory_map_role role)
126 : : {
127 : : struct spdk_rdma_mem_map *map;
128 : :
129 [ - + ]: 1019 : pthread_mutex_lock(&g_rdma_mr_maps_mutex);
130 : : /* Look up existing mem map registration for this pd */
131 [ + + ]: 1065 : LIST_FOREACH(map, &g_rdma_mr_maps, link) {
132 [ + + + - ]: 833 : if (map->pd == pd && map->role == role) {
133 : 787 : map->ref_count++;
134 [ - + ]: 787 : pthread_mutex_unlock(&g_rdma_mr_maps_mutex);
135 : 787 : return map;
136 : : }
137 : : }
138 : :
139 [ + - ]: 232 : if (hooks) {
140 : 232 : map = spdk_zmalloc(sizeof(*map), 0, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
141 : : } else {
142 : 0 : map = calloc(1, sizeof(*map));
143 : : }
144 [ - + ]: 232 : if (!map) {
145 [ # # ]: 0 : pthread_mutex_unlock(&g_rdma_mr_maps_mutex);
146 : 0 : SPDK_ERRLOG("Memory allocation failed\n");
147 : 0 : return NULL;
148 : : }
149 : 232 : map->pd = pd;
150 : 232 : map->ref_count = 1;
151 : 232 : map->hooks = hooks;
152 : 232 : map->role = role;
153 : 232 : map->map = spdk_mem_map_alloc(0, &g_rdma_map_ops, map);
154 [ - + ]: 232 : if (!map->map) {
155 : 0 : SPDK_ERRLOG("Unable to create memory map\n");
156 : 0 : _rdma_free_mem_map(map);
157 [ # # ]: 0 : pthread_mutex_unlock(&g_rdma_mr_maps_mutex);
158 : 0 : return NULL;
159 : : }
160 [ + + ]: 232 : LIST_INSERT_HEAD(&g_rdma_mr_maps, map, link);
161 : :
162 [ - + ]: 232 : pthread_mutex_unlock(&g_rdma_mr_maps_mutex);
163 : :
164 : 232 : return map;
165 : : }
166 : :
167 : : void
168 : 1034 : spdk_rdma_free_mem_map(struct spdk_rdma_mem_map **_map)
169 : : {
170 : : struct spdk_rdma_mem_map *map;
171 : :
172 [ - + ]: 1034 : if (!_map) {
173 : 0 : return;
174 : : }
175 : :
176 : 1034 : map = *_map;
177 [ + + ]: 1034 : if (!map) {
178 : 15 : return;
179 : : }
180 : 1019 : *_map = NULL;
181 : :
182 [ - + ]: 1019 : pthread_mutex_lock(&g_rdma_mr_maps_mutex);
183 [ - + ]: 1019 : assert(map->ref_count > 0);
184 : 1019 : map->ref_count--;
185 [ + + ]: 1019 : if (map->ref_count != 0) {
186 [ - + ]: 787 : pthread_mutex_unlock(&g_rdma_mr_maps_mutex);
187 : 787 : return;
188 : : }
189 : :
190 [ + + ]: 232 : LIST_REMOVE(map, link);
191 [ - + ]: 232 : pthread_mutex_unlock(&g_rdma_mr_maps_mutex);
192 [ + - ]: 232 : if (map->map) {
193 : 232 : spdk_mem_map_free(&map->map);
194 : : }
195 : 232 : _rdma_free_mem_map(map);
196 : : }
197 : :
198 : : int
199 : 26126908 : spdk_rdma_get_translation(struct spdk_rdma_mem_map *map, void *address,
200 : : size_t length, struct spdk_rdma_memory_translation *translation)
201 : : {
202 : 26126908 : uint64_t real_length = length;
203 : :
204 [ - + ]: 26126908 : assert(map);
205 [ - + ]: 26126908 : assert(address);
206 [ - + ]: 26126908 : assert(translation);
207 : :
208 [ + - - + ]: 26126908 : if (map->hooks && map->hooks->get_rkey) {
209 : 0 : translation->translation_type = SPDK_RDMA_TRANSLATION_KEY;
210 : 0 : translation->mr_or_key.key = spdk_mem_map_translate(map->map, (uint64_t)address, &real_length);
211 : : } else {
212 : 26126908 : translation->translation_type = SPDK_RDMA_TRANSLATION_MR;
213 : 26126908 : translation->mr_or_key.mr = (struct ibv_mr *)spdk_mem_map_translate(map->map, (uint64_t)address,
214 : : &real_length);
215 [ - + ]: 26126908 : if (spdk_unlikely(!translation->mr_or_key.mr)) {
216 : 0 : SPDK_ERRLOG("No translation for ptr %p, size %zu\n", address, length);
217 : 0 : return -EINVAL;
218 : : }
219 : : }
220 : :
221 [ - + ]: 26126908 : assert(real_length >= length);
222 : :
223 : 26126908 : return 0;
224 : : }
225 : :
226 : : struct spdk_rdma_srq *
227 : 252 : spdk_rdma_srq_create(struct spdk_rdma_srq_init_attr *init_attr)
228 : : {
229 [ - + ]: 252 : assert(init_attr);
230 [ - + ]: 252 : assert(init_attr->pd);
231 : :
232 : 252 : struct spdk_rdma_srq *rdma_srq = calloc(1, sizeof(*rdma_srq));
233 : :
234 [ - + ]: 252 : if (!rdma_srq) {
235 : 0 : SPDK_ERRLOG("Can't allocate memory for SRQ handle\n");
236 : 0 : return NULL;
237 : : }
238 : :
239 [ + - ]: 252 : if (init_attr->stats) {
240 : 252 : rdma_srq->stats = init_attr->stats;
241 : 252 : rdma_srq->shared_stats = true;
242 : : } else {
243 : 0 : rdma_srq->stats = calloc(1, sizeof(*rdma_srq->stats));
244 [ # # ]: 0 : if (!rdma_srq->stats) {
245 : 0 : SPDK_ERRLOG("SRQ statistics memory allocation failed");
246 : 0 : free(rdma_srq);
247 : 0 : return NULL;
248 : : }
249 : : }
250 : :
251 : 252 : rdma_srq->srq = ibv_create_srq(init_attr->pd, &init_attr->srq_init_attr);
252 [ - + ]: 252 : if (!rdma_srq->srq) {
253 [ # # ]: 0 : if (!init_attr->stats) {
254 : 0 : free(rdma_srq->stats);
255 : : }
256 : 0 : SPDK_ERRLOG("Unable to create SRQ, errno %d (%s)\n", errno, spdk_strerror(errno));
257 : 0 : free(rdma_srq);
258 : 0 : return NULL;
259 : : }
260 : :
261 : 252 : return rdma_srq;
262 : : }
263 : :
264 : : int
265 : 252 : spdk_rdma_srq_destroy(struct spdk_rdma_srq *rdma_srq)
266 : : {
267 : : int rc;
268 : :
269 [ - + ]: 252 : if (!rdma_srq) {
270 : 0 : return 0;
271 : : }
272 : :
273 [ - + ]: 252 : assert(rdma_srq->srq);
274 : :
275 [ - + ]: 252 : if (rdma_srq->recv_wrs.first != NULL) {
276 : 0 : SPDK_WARNLOG("Destroying RDMA SRQ with queued recv WRs\n");
277 : : }
278 : :
279 : 252 : rc = ibv_destroy_srq(rdma_srq->srq);
280 [ - + ]: 252 : if (rc) {
281 : 0 : SPDK_ERRLOG("SRQ destroy failed with %d\n", rc);
282 : : }
283 : :
284 [ - + - + ]: 252 : if (!rdma_srq->shared_stats) {
285 : 0 : free(rdma_srq->stats);
286 : : }
287 : :
288 : 252 : free(rdma_srq);
289 : :
290 : 252 : return rc;
291 : : }
292 : :
293 : : static inline bool
294 : 14666299 : rdma_queue_recv_wrs(struct spdk_rdma_recv_wr_list *recv_wrs, struct ibv_recv_wr *first,
295 : : struct spdk_rdma_wr_stats *recv_stats)
296 : : {
297 : : struct ibv_recv_wr *last;
298 : :
299 : 14666299 : recv_stats->num_submitted_wrs++;
300 : 14666299 : last = first;
301 [ - + ]: 14666299 : while (last->next != NULL) {
302 : 0 : last = last->next;
303 : 0 : recv_stats->num_submitted_wrs++;
304 : : }
305 : :
306 [ + + ]: 14666299 : if (recv_wrs->first == NULL) {
307 : 3104724 : recv_wrs->first = first;
308 : 3104724 : recv_wrs->last = last;
309 : 3104724 : return true;
310 : : } else {
311 : 11561575 : recv_wrs->last->next = first;
312 : 11561575 : recv_wrs->last = last;
313 : 11561575 : return false;
314 : : }
315 : : }
316 : :
317 : : bool
318 : 7758015 : spdk_rdma_srq_queue_recv_wrs(struct spdk_rdma_srq *rdma_srq, struct ibv_recv_wr *first)
319 : : {
320 [ - + ]: 7758015 : assert(rdma_srq);
321 [ - + ]: 7758015 : assert(first);
322 : :
323 : 7758015 : return rdma_queue_recv_wrs(&rdma_srq->recv_wrs, first, rdma_srq->stats);
324 : : }
325 : :
326 : : int
327 : 683194694 : spdk_rdma_srq_flush_recv_wrs(struct spdk_rdma_srq *rdma_srq, struct ibv_recv_wr **bad_wr)
328 : : {
329 : : int rc;
330 : :
331 [ + + ]: 683194694 : if (spdk_unlikely(rdma_srq->recv_wrs.first == NULL)) {
332 : 682216033 : return 0;
333 : : }
334 : :
335 : 978661 : rc = ibv_post_srq_recv(rdma_srq->srq, rdma_srq->recv_wrs.first, bad_wr);
336 : :
337 : 978661 : rdma_srq->recv_wrs.first = NULL;
338 : 978661 : rdma_srq->stats->doorbell_updates++;
339 : :
340 : 978661 : return rc;
341 : : }
342 : :
343 : : bool
344 : 6908284 : spdk_rdma_qp_queue_recv_wrs(struct spdk_rdma_qp *spdk_rdma_qp, struct ibv_recv_wr *first)
345 : : {
346 [ - + ]: 6908284 : assert(spdk_rdma_qp);
347 [ - + ]: 6908284 : assert(first);
348 : :
349 : 6908284 : return rdma_queue_recv_wrs(&spdk_rdma_qp->recv_wrs, first, &spdk_rdma_qp->stats->recv);
350 : : }
351 : :
352 : : int
353 : 104034741 : spdk_rdma_qp_flush_recv_wrs(struct spdk_rdma_qp *spdk_rdma_qp, struct ibv_recv_wr **bad_wr)
354 : : {
355 : : int rc;
356 : :
357 [ + + ]: 104034741 : if (spdk_unlikely(spdk_rdma_qp->recv_wrs.first == NULL)) {
358 : 101908678 : return 0;
359 : : }
360 : :
361 : 2126063 : rc = ibv_post_recv(spdk_rdma_qp->qp, spdk_rdma_qp->recv_wrs.first, bad_wr);
362 : :
363 : 2126063 : spdk_rdma_qp->recv_wrs.first = NULL;
364 : 2126063 : spdk_rdma_qp->stats->recv.doorbell_updates++;
365 : :
366 : 2126063 : return rc;
367 : : }
368 : :
369 : : static struct spdk_rdma_device *
370 : 120 : rdma_add_dev(struct ibv_context *context)
371 : : {
372 : : struct spdk_rdma_device *dev;
373 : :
374 : 120 : dev = calloc(1, sizeof(*dev));
375 [ - + ]: 120 : if (dev == NULL) {
376 : 0 : SPDK_ERRLOG("Failed to allocate RDMA device object.\n");
377 : 0 : return NULL;
378 : : }
379 : :
380 : 120 : dev->pd = ibv_alloc_pd(context);
381 [ - + ]: 120 : if (dev->pd == NULL) {
382 : 0 : SPDK_ERRLOG("ibv_alloc_pd() failed: %s (%d)\n", spdk_strerror(errno), errno);
383 : 0 : free(dev);
384 : 0 : return NULL;
385 : : }
386 : :
387 : 120 : dev->context = context;
388 : 120 : TAILQ_INSERT_TAIL(&g_dev_list, dev, tailq);
389 : :
390 : 120 : return dev;
391 : : }
392 : :
393 : : static void
394 : 1088 : rdma_remove_dev(struct spdk_rdma_device *dev)
395 : : {
396 [ + + + + : 1088 : if (!dev->removed || dev->ref > 0) {
+ + ]
397 : 968 : return;
398 : : }
399 : :
400 : : /* Deallocate protection domain only if the device is already removed and
401 : : * there is no reference.
402 : : */
403 [ + + ]: 120 : TAILQ_REMOVE(&g_dev_list, dev, tailq);
404 : 120 : ibv_dealloc_pd(dev->pd);
405 : 120 : free(dev);
406 : : }
407 : :
408 : : static int
409 : 1932 : ctx_cmp(const void *_c1, const void *_c2)
410 : : {
411 : 1932 : struct ibv_context *c1 = *(struct ibv_context **)_c1;
412 : 1932 : struct ibv_context *c2 = *(struct ibv_context **)_c2;
413 : :
414 [ + + ]: 1932 : return c1 < c2 ? -1 : c1 > c2;
415 : : }
416 : :
417 : : static int
418 : 1948 : rdma_sync_dev_list(void)
419 : : {
420 : : struct ibv_context **new_ctx_list;
421 : : int i, j;
422 : 1948 : int num_devs = 0;
423 : :
424 : : /*
425 : : * rdma_get_devices() returns a NULL terminated array of opened RDMA devices,
426 : : * and sets num_devs to the number of the returned devices.
427 : : */
428 : 1948 : new_ctx_list = rdma_get_devices(&num_devs);
429 [ - + ]: 1948 : if (new_ctx_list == NULL) {
430 : 0 : SPDK_ERRLOG("rdma_get_devices() failed: %s (%d)\n", spdk_strerror(errno), errno);
431 : 0 : return -ENODEV;
432 : : }
433 : :
434 [ - + ]: 1948 : if (num_devs == 0) {
435 : 0 : rdma_free_devices(new_ctx_list);
436 : 0 : SPDK_ERRLOG("Returned RDMA device array was empty\n");
437 : 0 : return -ENODEV;
438 : : }
439 : :
440 : : /*
441 : : * Sort new_ctx_list by addresses to update devices easily.
442 : : */
443 [ - + ]: 1948 : qsort(new_ctx_list, num_devs, sizeof(struct ibv_context *), ctx_cmp);
444 : :
445 [ + + ]: 1948 : if (g_ctx_list == NULL) {
446 : : /* If no old array, this is the first call. Add all devices. */
447 [ + + ]: 171 : for (i = 0; new_ctx_list[i] != NULL; i++) {
448 : 114 : rdma_add_dev(new_ctx_list[i]);
449 : : }
450 : :
451 : 57 : goto exit;
452 : : }
453 : :
454 [ + + + + ]: 5661 : for (i = j = 0; new_ctx_list[i] != NULL || g_ctx_list[j] != NULL;) {
455 : 3770 : struct ibv_context *new_ctx = new_ctx_list[i];
456 : 3770 : struct ibv_context *old_ctx = g_ctx_list[j];
457 : 3770 : bool add = false, remove = false;
458 : :
459 : : /*
460 : : * If a context exists only in the new array, create a device for it,
461 : : * or if a context exists only in the old array, try removing the
462 : : * corresponding device.
463 : : */
464 : :
465 [ - + ]: 3770 : if (old_ctx == NULL) {
466 : 0 : add = true;
467 [ + + ]: 3770 : } else if (new_ctx == NULL) {
468 : 6 : remove = true;
469 [ + + ]: 3764 : } else if (new_ctx < old_ctx) {
470 : 6 : add = true;
471 [ + + ]: 3758 : } else if (old_ctx < new_ctx) {
472 : 6 : remove = true;
473 : : }
474 : :
475 [ + + ]: 3770 : if (add) {
476 : 6 : rdma_add_dev(new_ctx_list[i]);
477 : 6 : i++;
478 [ + + ]: 3764 : } else if (remove) {
479 : : struct spdk_rdma_device *dev, *tmp;
480 : :
481 [ + + ]: 42 : TAILQ_FOREACH_SAFE(dev, &g_dev_list, tailq, tmp) {
482 [ + + ]: 30 : if (dev->context == g_ctx_list[j]) {
483 : 12 : dev->removed = true;
484 : 12 : rdma_remove_dev(dev);
485 : : }
486 : : }
487 : 12 : j++;
488 : : } else {
489 : 3752 : i++;
490 : 3752 : j++;
491 : : }
492 : : }
493 : :
494 : : /* Free the old array. */
495 : 1891 : rdma_free_devices(g_ctx_list);
496 : :
497 : 1948 : exit:
498 : : /*
499 : : * Keep the newly returned array so that allocated protection domains
500 : : * are not freed unexpectedly.
501 : : */
502 : 1948 : g_ctx_list = new_ctx_list;
503 : 1948 : return 0;
504 : : }
505 : :
506 : : struct ibv_pd *
507 : 980 : spdk_rdma_get_pd(struct ibv_context *context)
508 : : {
509 : : struct spdk_rdma_device *dev;
510 : : int rc;
511 : :
512 [ - + ]: 980 : pthread_mutex_lock(&g_dev_mutex);
513 : :
514 : 980 : rc = rdma_sync_dev_list();
515 [ - + ]: 980 : if (rc != 0) {
516 [ # # ]: 0 : pthread_mutex_unlock(&g_dev_mutex);
517 : :
518 : 0 : SPDK_ERRLOG("Failed to sync RDMA device list\n");
519 : 0 : return NULL;
520 : : }
521 : :
522 [ + + ]: 1006 : TAILQ_FOREACH(dev, &g_dev_list, tailq) {
523 [ + + + + : 994 : if (dev->context == context && !dev->removed) {
+ + ]
524 : 968 : dev->ref++;
525 [ - + ]: 968 : pthread_mutex_unlock(&g_dev_mutex);
526 : :
527 : 968 : return dev->pd;
528 : : }
529 : : }
530 : :
531 [ - + ]: 12 : pthread_mutex_unlock(&g_dev_mutex);
532 : :
533 : 12 : SPDK_ERRLOG("Failed to get PD\n");
534 : 12 : return NULL;
535 : : }
536 : :
537 : : void
538 : 968 : spdk_rdma_put_pd(struct ibv_pd *pd)
539 : : {
540 : : struct spdk_rdma_device *dev, *tmp;
541 : :
542 [ - + ]: 968 : pthread_mutex_lock(&g_dev_mutex);
543 : :
544 [ + + ]: 2898 : TAILQ_FOREACH_SAFE(dev, &g_dev_list, tailq, tmp) {
545 [ + + ]: 1930 : if (dev->pd == pd) {
546 [ - + ]: 968 : assert(dev->ref > 0);
547 : 968 : dev->ref--;
548 : :
549 : 968 : rdma_remove_dev(dev);
550 : : }
551 : : }
552 : :
553 : 968 : rdma_sync_dev_list();
554 : :
555 [ - + ]: 968 : pthread_mutex_unlock(&g_dev_mutex);
556 : 968 : }
557 : :
558 : : __attribute__((destructor)) static void
559 : 2472 : _rdma_fini(void)
560 : : {
561 : : struct spdk_rdma_device *dev, *tmp;
562 : :
563 [ + + ]: 2580 : TAILQ_FOREACH_SAFE(dev, &g_dev_list, tailq, tmp) {
564 : 108 : dev->removed = true;
565 : 108 : dev->ref = 0;
566 : 108 : rdma_remove_dev(dev);
567 : : }
568 : :
569 [ + + ]: 2472 : if (g_ctx_list != NULL) {
570 : 57 : rdma_free_devices(g_ctx_list);
571 : 57 : g_ctx_list = NULL;
572 : : }
573 : 2472 : }
|