mem: add function for checking memseg IOVA
[dpdk.git] / lib / librte_eal / common / eal_common_memory.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #include <fcntl.h>
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 #include <stdarg.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <inttypes.h>
14 #include <sys/mman.h>
15 #include <sys/queue.h>
16
17 #include <rte_fbarray.h>
18 #include <rte_memory.h>
19 #include <rte_eal.h>
20 #include <rte_eal_memconfig.h>
21 #include <rte_errno.h>
22 #include <rte_log.h>
23
24 #include "eal_memalloc.h"
25 #include "eal_private.h"
26 #include "eal_internal_cfg.h"
27
28 /*
29  * Try to mmap *size bytes in /dev/zero. If it is successful, return the
30  * pointer to the mmap'd area and keep *size unmodified. Else, retry
31  * with a smaller zone: decrease *size by hugepage_sz until it reaches
32  * 0. In this case, return NULL. Note: this function returns an address
33  * which is a multiple of hugepage size.
34  */
35
36 #define MEMSEG_LIST_FMT "memseg-%" PRIu64 "k-%i-%i"
37
38 static void *next_baseaddr;
39 static uint64_t system_page_sz;
40
41 void *
42 eal_get_virtual_area(void *requested_addr, size_t *size,
43                 size_t page_sz, int flags, int mmap_flags)
44 {
45         bool addr_is_hint, allow_shrink, unmap, no_align;
46         uint64_t map_sz;
47         void *mapped_addr, *aligned_addr;
48
49         if (system_page_sz == 0)
50                 system_page_sz = sysconf(_SC_PAGESIZE);
51
52         mmap_flags |= MAP_PRIVATE | MAP_ANONYMOUS;
53
54         RTE_LOG(DEBUG, EAL, "Ask a virtual area of 0x%zx bytes\n", *size);
55
56         addr_is_hint = (flags & EAL_VIRTUAL_AREA_ADDR_IS_HINT) > 0;
57         allow_shrink = (flags & EAL_VIRTUAL_AREA_ALLOW_SHRINK) > 0;
58         unmap = (flags & EAL_VIRTUAL_AREA_UNMAP) > 0;
59
60         if (next_baseaddr == NULL && internal_config.base_virtaddr != 0 &&
61                         rte_eal_process_type() == RTE_PROC_PRIMARY)
62                 next_baseaddr = (void *) internal_config.base_virtaddr;
63
64         if (requested_addr == NULL && next_baseaddr != NULL) {
65                 requested_addr = next_baseaddr;
66                 requested_addr = RTE_PTR_ALIGN(requested_addr, page_sz);
67                 addr_is_hint = true;
68         }
69
70         /* we don't need alignment of resulting pointer in the following cases:
71          *
72          * 1. page size is equal to system size
73          * 2. we have a requested address, and it is page-aligned, and we will
74          *    be discarding the address if we get a different one.
75          *
76          * for all other cases, alignment is potentially necessary.
77          */
78         no_align = (requested_addr != NULL &&
79                 requested_addr == RTE_PTR_ALIGN(requested_addr, page_sz) &&
80                 !addr_is_hint) ||
81                 page_sz == system_page_sz;
82
83         do {
84                 map_sz = no_align ? *size : *size + page_sz;
85                 if (map_sz > SIZE_MAX) {
86                         RTE_LOG(ERR, EAL, "Map size too big\n");
87                         rte_errno = E2BIG;
88                         return NULL;
89                 }
90
91                 mapped_addr = mmap(requested_addr, (size_t)map_sz, PROT_READ,
92                                 mmap_flags, -1, 0);
93                 if (mapped_addr == MAP_FAILED && allow_shrink)
94                         *size -= page_sz;
95         } while (allow_shrink && mapped_addr == MAP_FAILED && *size > 0);
96
97         /* align resulting address - if map failed, we will ignore the value
98          * anyway, so no need to add additional checks.
99          */
100         aligned_addr = no_align ? mapped_addr :
101                         RTE_PTR_ALIGN(mapped_addr, page_sz);
102
103         if (*size == 0) {
104                 RTE_LOG(ERR, EAL, "Cannot get a virtual area of any size: %s\n",
105                         strerror(errno));
106                 rte_errno = errno;
107                 return NULL;
108         } else if (mapped_addr == MAP_FAILED) {
109                 RTE_LOG(ERR, EAL, "Cannot get a virtual area: %s\n",
110                         strerror(errno));
111                 /* pass errno up the call chain */
112                 rte_errno = errno;
113                 return NULL;
114         } else if (requested_addr != NULL && !addr_is_hint &&
115                         aligned_addr != requested_addr) {
116                 RTE_LOG(ERR, EAL, "Cannot get a virtual area at requested address: %p (got %p)\n",
117                         requested_addr, aligned_addr);
118                 munmap(mapped_addr, map_sz);
119                 rte_errno = EADDRNOTAVAIL;
120                 return NULL;
121         } else if (requested_addr != NULL && addr_is_hint &&
122                         aligned_addr != requested_addr) {
123                 RTE_LOG(WARNING, EAL, "WARNING! Base virtual address hint (%p != %p) not respected!\n",
124                         requested_addr, aligned_addr);
125                 RTE_LOG(WARNING, EAL, "   This may cause issues with mapping memory into secondary processes\n");
126         } else if (next_baseaddr != NULL) {
127                 next_baseaddr = RTE_PTR_ADD(aligned_addr, *size);
128         }
129
130         RTE_LOG(DEBUG, EAL, "Virtual area found at %p (size = 0x%zx)\n",
131                 aligned_addr, *size);
132
133         if (unmap) {
134                 munmap(mapped_addr, map_sz);
135         } else if (!no_align) {
136                 void *map_end, *aligned_end;
137                 size_t before_len, after_len;
138
139                 /* when we reserve space with alignment, we add alignment to
140                  * mapping size. On 32-bit, if 1GB alignment was requested, this
141                  * would waste 1GB of address space, which is a luxury we cannot
142                  * afford. so, if alignment was performed, check if any unneeded
143                  * address space can be unmapped back.
144                  */
145
146                 map_end = RTE_PTR_ADD(mapped_addr, (size_t)map_sz);
147                 aligned_end = RTE_PTR_ADD(aligned_addr, *size);
148
149                 /* unmap space before aligned mmap address */
150                 before_len = RTE_PTR_DIFF(aligned_addr, mapped_addr);
151                 if (before_len > 0)
152                         munmap(mapped_addr, before_len);
153
154                 /* unmap space after aligned end mmap address */
155                 after_len = RTE_PTR_DIFF(map_end, aligned_end);
156                 if (after_len > 0)
157                         munmap(aligned_end, after_len);
158         }
159
160         return aligned_addr;
161 }
162
163 static struct rte_memseg *
164 virt2memseg(const void *addr, const struct rte_memseg_list *msl)
165 {
166         const struct rte_fbarray *arr;
167         void *start, *end;
168         int ms_idx;
169
170         if (msl == NULL)
171                 return NULL;
172
173         /* a memseg list was specified, check if it's the right one */
174         start = msl->base_va;
175         end = RTE_PTR_ADD(start, msl->len);
176
177         if (addr < start || addr >= end)
178                 return NULL;
179
180         /* now, calculate index */
181         arr = &msl->memseg_arr;
182         ms_idx = RTE_PTR_DIFF(addr, msl->base_va) / msl->page_sz;
183         return rte_fbarray_get(arr, ms_idx);
184 }
185
186 static struct rte_memseg_list *
187 virt2memseg_list(const void *addr)
188 {
189         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
190         struct rte_memseg_list *msl;
191         int msl_idx;
192
193         for (msl_idx = 0; msl_idx < RTE_MAX_MEMSEG_LISTS; msl_idx++) {
194                 void *start, *end;
195                 msl = &mcfg->memsegs[msl_idx];
196
197                 start = msl->base_va;
198                 end = RTE_PTR_ADD(start, msl->len);
199                 if (addr >= start && addr < end)
200                         break;
201         }
202         /* if we didn't find our memseg list */
203         if (msl_idx == RTE_MAX_MEMSEG_LISTS)
204                 return NULL;
205         return msl;
206 }
207
208 __rte_experimental struct rte_memseg_list *
209 rte_mem_virt2memseg_list(const void *addr)
210 {
211         return virt2memseg_list(addr);
212 }
213
214 struct virtiova {
215         rte_iova_t iova;
216         void *virt;
217 };
218 static int
219 find_virt(const struct rte_memseg_list *msl __rte_unused,
220                 const struct rte_memseg *ms, void *arg)
221 {
222         struct virtiova *vi = arg;
223         if (vi->iova >= ms->iova && vi->iova < (ms->iova + ms->len)) {
224                 size_t offset = vi->iova - ms->iova;
225                 vi->virt = RTE_PTR_ADD(ms->addr, offset);
226                 /* stop the walk */
227                 return 1;
228         }
229         return 0;
230 }
231 static int
232 find_virt_legacy(const struct rte_memseg_list *msl __rte_unused,
233                 const struct rte_memseg *ms, size_t len, void *arg)
234 {
235         struct virtiova *vi = arg;
236         if (vi->iova >= ms->iova && vi->iova < (ms->iova + len)) {
237                 size_t offset = vi->iova - ms->iova;
238                 vi->virt = RTE_PTR_ADD(ms->addr, offset);
239                 /* stop the walk */
240                 return 1;
241         }
242         return 0;
243 }
244
245 __rte_experimental void *
246 rte_mem_iova2virt(rte_iova_t iova)
247 {
248         struct virtiova vi;
249
250         memset(&vi, 0, sizeof(vi));
251
252         vi.iova = iova;
253         /* for legacy mem, we can get away with scanning VA-contiguous segments,
254          * as we know they are PA-contiguous as well
255          */
256         if (internal_config.legacy_mem)
257                 rte_memseg_contig_walk(find_virt_legacy, &vi);
258         else
259                 rte_memseg_walk(find_virt, &vi);
260
261         return vi.virt;
262 }
263
264 __rte_experimental struct rte_memseg *
265 rte_mem_virt2memseg(const void *addr, const struct rte_memseg_list *msl)
266 {
267         return virt2memseg(addr, msl != NULL ? msl :
268                         rte_mem_virt2memseg_list(addr));
269 }
270
271 static int
272 physmem_size(const struct rte_memseg_list *msl, void *arg)
273 {
274         uint64_t *total_len = arg;
275
276         if (msl->external)
277                 return 0;
278
279         *total_len += msl->memseg_arr.count * msl->page_sz;
280
281         return 0;
282 }
283
284 /* get the total size of memory */
285 uint64_t
286 rte_eal_get_physmem_size(void)
287 {
288         uint64_t total_len = 0;
289
290         rte_memseg_list_walk(physmem_size, &total_len);
291
292         return total_len;
293 }
294
295 static int
296 dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
297                 void *arg)
298 {
299         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
300         int msl_idx, ms_idx, fd;
301         FILE *f = arg;
302
303         msl_idx = msl - mcfg->memsegs;
304         if (msl_idx < 0 || msl_idx >= RTE_MAX_MEMSEG_LISTS)
305                 return -1;
306
307         ms_idx = rte_fbarray_find_idx(&msl->memseg_arr, ms);
308         if (ms_idx < 0)
309                 return -1;
310
311         fd = eal_memalloc_get_seg_fd(msl_idx, ms_idx);
312         fprintf(f, "Segment %i-%i: IOVA:0x%"PRIx64", len:%zu, "
313                         "virt:%p, socket_id:%"PRId32", "
314                         "hugepage_sz:%"PRIu64", nchannel:%"PRIx32", "
315                         "nrank:%"PRIx32" fd:%i\n",
316                         msl_idx, ms_idx,
317                         ms->iova,
318                         ms->len,
319                         ms->addr,
320                         ms->socket_id,
321                         ms->hugepage_sz,
322                         ms->nchannel,
323                         ms->nrank,
324                         fd);
325
326         return 0;
327 }
328
329 /*
330  * Defining here because declared in rte_memory.h, but the actual implementation
331  * is in eal_common_memalloc.c, like all other memalloc internals.
332  */
333 int __rte_experimental
334 rte_mem_event_callback_register(const char *name, rte_mem_event_callback_t clb,
335                 void *arg)
336 {
337         /* FreeBSD boots with legacy mem enabled by default */
338         if (internal_config.legacy_mem) {
339                 RTE_LOG(DEBUG, EAL, "Registering mem event callbacks not supported\n");
340                 rte_errno = ENOTSUP;
341                 return -1;
342         }
343         return eal_memalloc_mem_event_callback_register(name, clb, arg);
344 }
345
346 int __rte_experimental
347 rte_mem_event_callback_unregister(const char *name, void *arg)
348 {
349         /* FreeBSD boots with legacy mem enabled by default */
350         if (internal_config.legacy_mem) {
351                 RTE_LOG(DEBUG, EAL, "Registering mem event callbacks not supported\n");
352                 rte_errno = ENOTSUP;
353                 return -1;
354         }
355         return eal_memalloc_mem_event_callback_unregister(name, arg);
356 }
357
358 int __rte_experimental
359 rte_mem_alloc_validator_register(const char *name,
360                 rte_mem_alloc_validator_t clb, int socket_id, size_t limit)
361 {
362         /* FreeBSD boots with legacy mem enabled by default */
363         if (internal_config.legacy_mem) {
364                 RTE_LOG(DEBUG, EAL, "Registering mem alloc validators not supported\n");
365                 rte_errno = ENOTSUP;
366                 return -1;
367         }
368         return eal_memalloc_mem_alloc_validator_register(name, clb, socket_id,
369                         limit);
370 }
371
372 int __rte_experimental
373 rte_mem_alloc_validator_unregister(const char *name, int socket_id)
374 {
375         /* FreeBSD boots with legacy mem enabled by default */
376         if (internal_config.legacy_mem) {
377                 RTE_LOG(DEBUG, EAL, "Registering mem alloc validators not supported\n");
378                 rte_errno = ENOTSUP;
379                 return -1;
380         }
381         return eal_memalloc_mem_alloc_validator_unregister(name, socket_id);
382 }
383
384 /* Dump the physical memory layout on console */
385 void
386 rte_dump_physmem_layout(FILE *f)
387 {
388         rte_memseg_walk(dump_memseg, f);
389 }
390
391 static int
392 check_iova(const struct rte_memseg_list *msl __rte_unused,
393                 const struct rte_memseg *ms, void *arg)
394 {
395         uint64_t *mask = arg;
396         rte_iova_t iova;
397
398         /* higher address within segment */
399         iova = (ms->iova + ms->len) - 1;
400         if (!(iova & *mask))
401                 return 0;
402
403         RTE_LOG(DEBUG, EAL, "memseg iova %"PRIx64", len %zx, out of range\n",
404                             ms->iova, ms->len);
405
406         RTE_LOG(DEBUG, EAL, "\tusing dma mask %"PRIx64"\n", *mask);
407         return 1;
408 }
409
410 #if defined(RTE_ARCH_64)
411 #define MAX_DMA_MASK_BITS 63
412 #else
413 #define MAX_DMA_MASK_BITS 31
414 #endif
415
416 /* check memseg iovas are within the required range based on dma mask */
417 int __rte_experimental
418 rte_eal_check_dma_mask(uint8_t maskbits)
419 {
420         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
421         uint64_t mask;
422
423         /* sanity check */
424         if (maskbits > MAX_DMA_MASK_BITS) {
425                 RTE_LOG(ERR, EAL, "wrong dma mask size %u (Max: %u)\n",
426                                    maskbits, MAX_DMA_MASK_BITS);
427                 return -1;
428         }
429
430         /* create dma mask */
431         mask = ~((1ULL << maskbits) - 1);
432
433         if (rte_memseg_walk(check_iova, &mask))
434                 /*
435                  * Dma mask precludes hugepage usage.
436                  * This device can not be used and we do not need to keep
437                  * the dma mask.
438                  */
439                 return 1;
440
441         /*
442          * we need to keep the more restricted maskbit for checking
443          * potential dynamic memory allocation in the future.
444          */
445         mcfg->dma_maskbits = mcfg->dma_maskbits == 0 ? maskbits :
446                              RTE_MIN(mcfg->dma_maskbits, maskbits);
447
448         return 0;
449 }
450
451 /* return the number of memory channels */
452 unsigned rte_memory_get_nchannel(void)
453 {
454         return rte_eal_get_configuration()->mem_config->nchannel;
455 }
456
457 /* return the number of memory rank */
458 unsigned rte_memory_get_nrank(void)
459 {
460         return rte_eal_get_configuration()->mem_config->nrank;
461 }
462
463 static int
464 rte_eal_memdevice_init(void)
465 {
466         struct rte_config *config;
467
468         if (rte_eal_process_type() == RTE_PROC_SECONDARY)
469                 return 0;
470
471         config = rte_eal_get_configuration();
472         config->mem_config->nchannel = internal_config.force_nchannel;
473         config->mem_config->nrank = internal_config.force_nrank;
474
475         return 0;
476 }
477
478 /* Lock page in physical memory and prevent from swapping. */
479 int
480 rte_mem_lock_page(const void *virt)
481 {
482         unsigned long virtual = (unsigned long)virt;
483         int page_size = getpagesize();
484         unsigned long aligned = (virtual & ~(page_size - 1));
485         return mlock((void *)aligned, page_size);
486 }
487
488 int __rte_experimental
489 rte_memseg_contig_walk_thread_unsafe(rte_memseg_contig_walk_t func, void *arg)
490 {
491         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
492         int i, ms_idx, ret = 0;
493
494         for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
495                 struct rte_memseg_list *msl = &mcfg->memsegs[i];
496                 const struct rte_memseg *ms;
497                 struct rte_fbarray *arr;
498
499                 if (msl->memseg_arr.count == 0)
500                         continue;
501
502                 arr = &msl->memseg_arr;
503
504                 ms_idx = rte_fbarray_find_next_used(arr, 0);
505                 while (ms_idx >= 0) {
506                         int n_segs;
507                         size_t len;
508
509                         ms = rte_fbarray_get(arr, ms_idx);
510
511                         /* find how many more segments there are, starting with
512                          * this one.
513                          */
514                         n_segs = rte_fbarray_find_contig_used(arr, ms_idx);
515                         len = n_segs * msl->page_sz;
516
517                         ret = func(msl, ms, len, arg);
518                         if (ret)
519                                 return ret;
520                         ms_idx = rte_fbarray_find_next_used(arr,
521                                         ms_idx + n_segs);
522                 }
523         }
524         return 0;
525 }
526
527 int __rte_experimental
528 rte_memseg_contig_walk(rte_memseg_contig_walk_t func, void *arg)
529 {
530         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
531         int ret = 0;
532
533         /* do not allow allocations/frees/init while we iterate */
534         rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
535         ret = rte_memseg_contig_walk_thread_unsafe(func, arg);
536         rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
537
538         return ret;
539 }
540
541 int __rte_experimental
542 rte_memseg_walk_thread_unsafe(rte_memseg_walk_t func, void *arg)
543 {
544         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
545         int i, ms_idx, ret = 0;
546
547         for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
548                 struct rte_memseg_list *msl = &mcfg->memsegs[i];
549                 const struct rte_memseg *ms;
550                 struct rte_fbarray *arr;
551
552                 if (msl->memseg_arr.count == 0)
553                         continue;
554
555                 arr = &msl->memseg_arr;
556
557                 ms_idx = rte_fbarray_find_next_used(arr, 0);
558                 while (ms_idx >= 0) {
559                         ms = rte_fbarray_get(arr, ms_idx);
560                         ret = func(msl, ms, arg);
561                         if (ret)
562                                 return ret;
563                         ms_idx = rte_fbarray_find_next_used(arr, ms_idx + 1);
564                 }
565         }
566         return 0;
567 }
568
569 int __rte_experimental
570 rte_memseg_walk(rte_memseg_walk_t func, void *arg)
571 {
572         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
573         int ret = 0;
574
575         /* do not allow allocations/frees/init while we iterate */
576         rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
577         ret = rte_memseg_walk_thread_unsafe(func, arg);
578         rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
579
580         return ret;
581 }
582
583 int __rte_experimental
584 rte_memseg_list_walk_thread_unsafe(rte_memseg_list_walk_t func, void *arg)
585 {
586         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
587         int i, ret = 0;
588
589         for (i = 0; i < RTE_MAX_MEMSEG_LISTS; i++) {
590                 struct rte_memseg_list *msl = &mcfg->memsegs[i];
591
592                 if (msl->base_va == NULL)
593                         continue;
594
595                 ret = func(msl, arg);
596                 if (ret)
597                         return ret;
598         }
599         return 0;
600 }
601
602 int __rte_experimental
603 rte_memseg_list_walk(rte_memseg_list_walk_t func, void *arg)
604 {
605         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
606         int ret = 0;
607
608         /* do not allow allocations/frees/init while we iterate */
609         rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
610         ret = rte_memseg_list_walk_thread_unsafe(func, arg);
611         rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
612
613         return ret;
614 }
615
616 int __rte_experimental
617 rte_memseg_get_fd_thread_unsafe(const struct rte_memseg *ms)
618 {
619         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
620         struct rte_memseg_list *msl;
621         struct rte_fbarray *arr;
622         int msl_idx, seg_idx, ret;
623
624         if (ms == NULL) {
625                 rte_errno = EINVAL;
626                 return -1;
627         }
628
629         msl = rte_mem_virt2memseg_list(ms->addr);
630         if (msl == NULL) {
631                 rte_errno = EINVAL;
632                 return -1;
633         }
634         arr = &msl->memseg_arr;
635
636         msl_idx = msl - mcfg->memsegs;
637         seg_idx = rte_fbarray_find_idx(arr, ms);
638
639         if (!rte_fbarray_is_used(arr, seg_idx)) {
640                 rte_errno = ENOENT;
641                 return -1;
642         }
643
644         ret = eal_memalloc_get_seg_fd(msl_idx, seg_idx);
645         if (ret < 0) {
646                 rte_errno = -ret;
647                 ret = -1;
648         }
649         return ret;
650 }
651
652 int __rte_experimental
653 rte_memseg_get_fd(const struct rte_memseg *ms)
654 {
655         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
656         int ret;
657
658         rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
659         ret = rte_memseg_get_fd_thread_unsafe(ms);
660         rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
661
662         return ret;
663 }
664
665 int __rte_experimental
666 rte_memseg_get_fd_offset_thread_unsafe(const struct rte_memseg *ms,
667                 size_t *offset)
668 {
669         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
670         struct rte_memseg_list *msl;
671         struct rte_fbarray *arr;
672         int msl_idx, seg_idx, ret;
673
674         if (ms == NULL || offset == NULL) {
675                 rte_errno = EINVAL;
676                 return -1;
677         }
678
679         msl = rte_mem_virt2memseg_list(ms->addr);
680         if (msl == NULL) {
681                 rte_errno = EINVAL;
682                 return -1;
683         }
684         arr = &msl->memseg_arr;
685
686         msl_idx = msl - mcfg->memsegs;
687         seg_idx = rte_fbarray_find_idx(arr, ms);
688
689         if (!rte_fbarray_is_used(arr, seg_idx)) {
690                 rte_errno = ENOENT;
691                 return -1;
692         }
693
694         ret = eal_memalloc_get_seg_fd_offset(msl_idx, seg_idx, offset);
695         if (ret < 0) {
696                 rte_errno = -ret;
697                 ret = -1;
698         }
699         return ret;
700 }
701
702 int __rte_experimental
703 rte_memseg_get_fd_offset(const struct rte_memseg *ms, size_t *offset)
704 {
705         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
706         int ret;
707
708         rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
709         ret = rte_memseg_get_fd_offset_thread_unsafe(ms, offset);
710         rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
711
712         return ret;
713 }
714
715 /* init memory subsystem */
716 int
717 rte_eal_memory_init(void)
718 {
719         struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
720         int retval;
721         RTE_LOG(DEBUG, EAL, "Setting up physically contiguous memory...\n");
722
723         if (!mcfg)
724                 return -1;
725
726         /* lock mem hotplug here, to prevent races while we init */
727         rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
728
729         if (rte_eal_memseg_init() < 0)
730                 goto fail;
731
732         if (eal_memalloc_init() < 0)
733                 goto fail;
734
735         retval = rte_eal_process_type() == RTE_PROC_PRIMARY ?
736                         rte_eal_hugepage_init() :
737                         rte_eal_hugepage_attach();
738         if (retval < 0)
739                 goto fail;
740
741         if (internal_config.no_shconf == 0 && rte_eal_memdevice_init() < 0)
742                 goto fail;
743
744         return 0;
745 fail:
746         rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
747         return -1;
748 }