96fb0db5b733ee8724b5e396fd617525bd9028cc
[vpp.git] / src / vppinfra / linux / mem.c
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #define _GNU_SOURCE
17 #include <stdlib.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <sys/mount.h>
22 #include <sys/mman.h>
23 #include <fcntl.h>
24 #include <linux/mempolicy.h>
25 #include <linux/memfd.h>
26
27 #include <vppinfra/clib.h>
28 #include <vppinfra/mem.h>
29 #include <vppinfra/time.h>
30 #include <vppinfra/format.h>
31 #include <vppinfra/clib_error.h>
32 #include <vppinfra/linux/syscall.h>
33 #include <vppinfra/linux/sysfs.h>
34
35 #ifndef F_LINUX_SPECIFIC_BASE
36 #define F_LINUX_SPECIFIC_BASE 1024
37 #endif
38
39 #ifndef F_ADD_SEALS
40 #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
41 #define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
42
43 #define F_SEAL_SEAL     0x0001  /* prevent further seals from being set */
44 #define F_SEAL_SHRINK   0x0002  /* prevent file from shrinking */
45 #define F_SEAL_GROW     0x0004  /* prevent file from growing */
46 #define F_SEAL_WRITE    0x0008  /* prevent writes */
47 #endif
48
49 #ifndef MFD_HUGETLB
50 #define MFD_HUGETLB 0x0004U
51 #endif
52
53 #ifndef MAP_HUGE_SHIFT
54 #define MAP_HUGE_SHIFT 26
55 #endif
56
57 #ifndef MAP_FIXED_NOREPLACE
58 #define MAP_FIXED_NOREPLACE 0x100000
59 #endif
60
61 uword
62 clib_mem_get_default_hugepage_size (void)
63 {
64   unformat_input_t input;
65   static u32 size = 0;
66   int fd;
67
68   if (size)
69     goto done;
70
71   /*
72    * If the kernel doesn't support hugepages, /proc/meminfo won't
73    * say anything about it. Use the regular page size as a default.
74    */
75   size = clib_mem_get_page_size () / 1024;
76
77   if ((fd = open ("/proc/meminfo", 0)) == -1)
78     return 0;
79
80   unformat_init_clib_file (&input, fd);
81
82   while (unformat_check_input (&input) != UNFORMAT_END_OF_INPUT)
83     {
84       if (unformat (&input, "Hugepagesize:%_%u kB", &size))
85         ;
86       else
87         unformat_skip_line (&input);
88     }
89   unformat_free (&input);
90   close (fd);
91 done:
92   return 1024ULL * size;
93 }
94
95 static clib_mem_page_sz_t
96 legacy_get_log2_default_hugepage_size (void)
97 {
98   clib_mem_page_sz_t log2_page_size = CLIB_MEM_PAGE_SZ_UNKNOWN;
99   FILE *fp;
100   char tmp[33] = { };
101
102   if ((fp = fopen ("/proc/meminfo", "r")) == NULL)
103     return CLIB_MEM_PAGE_SZ_UNKNOWN;
104
105   while (fscanf (fp, "%32s", tmp) > 0)
106     if (strncmp ("Hugepagesize:", tmp, 13) == 0)
107       {
108         u32 size;
109         if (fscanf (fp, "%u", &size) > 0)
110           log2_page_size = 10 + min_log2 (size);
111         break;
112       }
113
114   fclose (fp);
115   return log2_page_size;
116 }
117
118 void
119 clib_mem_main_init ()
120 {
121   clib_mem_main_t *mm = &clib_mem_main;
122   uword page_size;
123   void *va;
124   int fd;
125
126   if (mm->log2_page_sz != CLIB_MEM_PAGE_SZ_UNKNOWN)
127     return;
128
129   /* system page size */
130   page_size = sysconf (_SC_PAGESIZE);
131   mm->log2_page_sz = min_log2 (page_size);
132
133   /* default system hugeppage size */
134   if ((fd = memfd_create ("test", MFD_HUGETLB)) != -1)
135     {
136       mm->log2_default_hugepage_sz = clib_mem_get_fd_log2_page_size (fd);
137       close (fd);
138     }
139   else                          /* likely kernel older than 4.14 */
140     mm->log2_default_hugepage_sz = legacy_get_log2_default_hugepage_size ();
141
142   /* numa nodes */
143   va = mmap (0, page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE |
144              MAP_ANONYMOUS, -1, 0);
145   if (va == MAP_FAILED)
146     return;
147
148   if (mlock (va, page_size))
149     goto done;
150
151   for (int i = 0; i < CLIB_MAX_NUMAS; i++)
152     {
153       int status;
154       if (move_pages (0, 1, &va, &i, &status, 0) == 0)
155         mm->numa_node_bitmap |= 1ULL << i;
156     }
157
158 done:
159   munmap (va, page_size);
160 }
161
162 u64
163 clib_mem_get_fd_page_size (int fd)
164 {
165   struct stat st = { 0 };
166   if (fstat (fd, &st) == -1)
167     return 0;
168   return st.st_blksize;
169 }
170
171 clib_mem_page_sz_t
172 clib_mem_get_fd_log2_page_size (int fd)
173 {
174   uword page_size = clib_mem_get_fd_page_size (fd);
175   return page_size ? min_log2 (page_size) : CLIB_MEM_PAGE_SZ_UNKNOWN;
176 }
177
178 void
179 clib_mem_vm_randomize_va (uword * requested_va,
180                           clib_mem_page_sz_t log2_page_size)
181 {
182   u8 bit_mask = 15;
183
184   if (log2_page_size <= 12)
185     bit_mask = 15;
186   else if (log2_page_size > 12 && log2_page_size <= 16)
187     bit_mask = 3;
188   else
189     bit_mask = 0;
190
191   *requested_va +=
192     (clib_cpu_time_now () & bit_mask) * (1ull << log2_page_size);
193 }
194
195 clib_error_t *
196 clib_mem_create_fd (char *name, int *fdp)
197 {
198   int fd;
199
200   ASSERT (name);
201
202   if ((fd = memfd_create (name, MFD_ALLOW_SEALING)) == -1)
203     return clib_error_return_unix (0, "memfd_create");
204
205   if ((fcntl (fd, F_ADD_SEALS, F_SEAL_SHRINK)) == -1)
206     {
207       close (fd);
208       return clib_error_return_unix (0, "fcntl (F_ADD_SEALS)");
209     }
210
211   *fdp = fd;
212   return 0;
213 }
214
215 clib_error_t *
216 clib_mem_create_hugetlb_fd (char *name, int *fdp)
217 {
218   clib_error_t *err = 0;
219   int fd = -1;
220   static int memfd_hugetlb_supported = 1;
221   char *mount_dir;
222   char template[] = "/tmp/hugepage_mount.XXXXXX";
223   u8 *filename;
224
225   ASSERT (name);
226
227   if (memfd_hugetlb_supported)
228     {
229       if ((fd = memfd_create (name, MFD_HUGETLB)) != -1)
230         goto done;
231
232       /* avoid further tries if memfd MFD_HUGETLB is not supported */
233       if (errno == EINVAL && strnlen (name, 256) <= 249)
234         memfd_hugetlb_supported = 0;
235     }
236
237   mount_dir = mkdtemp (template);
238   if (mount_dir == 0)
239     return clib_error_return_unix (0, "mkdtemp \'%s\'", template);
240
241   if (mount ("none", (char *) mount_dir, "hugetlbfs", 0, NULL))
242     {
243       rmdir ((char *) mount_dir);
244       err = clib_error_return_unix (0, "mount hugetlb directory '%s'",
245                                     mount_dir);
246     }
247
248   filename = format (0, "%s/%s%c", mount_dir, name, 0);
249   fd = open ((char *) filename, O_CREAT | O_RDWR, 0755);
250   umount2 ((char *) mount_dir, MNT_DETACH);
251   rmdir ((char *) mount_dir);
252
253   if (fd == -1)
254     err = clib_error_return_unix (0, "open");
255
256 done:
257   if (fd != -1)
258     fdp[0] = fd;
259   return err;
260 }
261
262 clib_error_t *
263 clib_mem_vm_ext_alloc (clib_mem_vm_alloc_t * a)
264 {
265   int fd = -1;
266   clib_error_t *err = 0;
267   void *addr = 0;
268   u8 *filename = 0;
269   int mmap_flags = 0;
270   int log2_page_size;
271   int n_pages;
272   int old_mpol = -1;
273   long unsigned int old_mask[16] = { 0 };
274
275   /* save old numa mem policy if needed */
276   if (a->flags & (CLIB_MEM_VM_F_NUMA_PREFER | CLIB_MEM_VM_F_NUMA_FORCE))
277     {
278       int rv;
279       rv = get_mempolicy (&old_mpol, old_mask, sizeof (old_mask) * 8 + 1,
280                           0, 0);
281
282       if (rv == -1)
283         {
284           if (a->numa_node != 0 && (a->flags & CLIB_MEM_VM_F_NUMA_FORCE) != 0)
285             {
286               err = clib_error_return_unix (0, "get_mempolicy");
287               goto error;
288             }
289           else
290             old_mpol = -1;
291         }
292     }
293
294   if (a->flags & CLIB_MEM_VM_F_LOCKED)
295     mmap_flags |= MAP_LOCKED;
296
297   /* if we are creating shared segment, we need file descriptor */
298   if (a->flags & CLIB_MEM_VM_F_SHARED)
299     {
300       mmap_flags |= MAP_SHARED;
301       /* if hugepages are needed we need to create mount point */
302       if (a->flags & CLIB_MEM_VM_F_HUGETLB)
303         {
304           if ((err = clib_mem_create_hugetlb_fd (a->name, &fd)))
305             goto error;
306
307           mmap_flags |= MAP_LOCKED;
308         }
309       else
310         {
311           if ((err = clib_mem_create_fd (a->name, &fd)))
312             goto error;
313         }
314
315       log2_page_size = clib_mem_get_fd_log2_page_size (fd);
316       if (log2_page_size == 0)
317         {
318           err = clib_error_return_unix (0, "cannot determine page size");
319           goto error;
320         }
321
322       if (a->requested_va)
323         {
324           clib_mem_vm_randomize_va (&a->requested_va, log2_page_size);
325           mmap_flags |= MAP_FIXED;
326         }
327     }
328   else                          /* not CLIB_MEM_VM_F_SHARED */
329     {
330       mmap_flags |= MAP_PRIVATE | MAP_ANONYMOUS;
331       if (a->flags & CLIB_MEM_VM_F_HUGETLB)
332         {
333           mmap_flags |= MAP_HUGETLB;
334           log2_page_size = 21;
335         }
336       else
337         {
338           log2_page_size = min_log2 (sysconf (_SC_PAGESIZE));
339         }
340     }
341
342   n_pages = ((a->size - 1) >> log2_page_size) + 1;
343
344   if (a->flags & CLIB_MEM_VM_F_HUGETLB_PREALLOC)
345     {
346       err = clib_sysfs_prealloc_hugepages (a->numa_node, log2_page_size,
347                                            n_pages);
348       if (err)
349         goto error;
350
351     }
352
353   if (fd != -1)
354     if ((ftruncate (fd, (u64) n_pages * (1 << log2_page_size))) == -1)
355       {
356         err = clib_error_return_unix (0, "ftruncate");
357         goto error;
358       }
359
360   if (old_mpol != -1)
361     {
362       int rv;
363       long unsigned int mask[16] = { 0 };
364       mask[0] = 1 << a->numa_node;
365       rv = set_mempolicy (MPOL_BIND, mask, sizeof (mask) * 8 + 1);
366       if (rv == -1 && a->numa_node != 0 &&
367           (a->flags & CLIB_MEM_VM_F_NUMA_FORCE) != 0)
368         {
369           err = clib_error_return_unix (0, "set_mempolicy");
370           goto error;
371         }
372     }
373
374   addr = mmap (uword_to_pointer (a->requested_va, void *), a->size,
375                (PROT_READ | PROT_WRITE), mmap_flags, fd, 0);
376   if (addr == MAP_FAILED)
377     {
378       err = clib_error_return_unix (0, "mmap");
379       goto error;
380     }
381
382   /* re-apply old numa memory policy */
383   if (old_mpol != -1 &&
384       set_mempolicy (old_mpol, old_mask, sizeof (old_mask) * 8 + 1) == -1)
385     {
386       err = clib_error_return_unix (0, "set_mempolicy");
387       goto error;
388     }
389
390   a->log2_page_size = log2_page_size;
391   a->n_pages = n_pages;
392   a->addr = addr;
393   a->fd = fd;
394   CLIB_MEM_UNPOISON (addr, a->size);
395   goto done;
396
397 error:
398   if (fd != -1)
399     close (fd);
400
401 done:
402   vec_free (filename);
403   return err;
404 }
405
406 void
407 clib_mem_vm_ext_free (clib_mem_vm_alloc_t * a)
408 {
409   if (a != 0)
410     {
411       clib_mem_vm_free (a->addr, 1ull << a->log2_page_size);
412       if (a->fd != -1)
413         close (a->fd);
414     }
415 }
416
417 uword
418 clib_mem_vm_reserve (uword start, uword size, clib_mem_page_sz_t log2_page_sz)
419 {
420   clib_mem_main_t *mm = &clib_mem_main;
421   uword pagesize = 1ULL << log2_page_sz;
422   uword sys_page_sz = 1ULL << mm->log2_page_sz;
423   uword n_bytes;
424   void *base = 0, *p;
425
426   size = round_pow2 (size, pagesize);
427
428   /* in adition of requested reservation, we also rserve one system page
429    * (typically 4K) adjacent to the start off reservation */
430
431   if (start)
432     {
433       /* start address is provided, so we just need to make sure we are not
434        * replacing existing map */
435       if (start & pow2_mask (log2_page_sz))
436         return ~0;
437
438       base = (void *) start - sys_page_sz;
439       base = mmap (base, size + sys_page_sz, PROT_NONE,
440                    MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE, -1, 0);
441       return (base == MAP_FAILED) ? ~0 : start;
442     }
443
444   /* to make sure that we get reservation aligned to page_size we need to
445    * request one additional page as mmap will return us address which is
446    * aligned only to system page size */
447   base = mmap (0, size + pagesize, PROT_NONE,
448                MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
449
450   if (base == MAP_FAILED)
451     return ~0;
452
453   /* return additional space at the end of allocation */
454   p = base + size + pagesize;
455   n_bytes = (uword) p & pow2_mask (log2_page_sz);
456   if (n_bytes)
457     {
458       p -= n_bytes;
459       munmap (p, n_bytes);
460     }
461
462   /* return additional space at the start of allocation */
463   n_bytes = pagesize - sys_page_sz - n_bytes;
464   if (n_bytes)
465     {
466       munmap (base, n_bytes);
467       base += n_bytes;
468     }
469
470   return (uword) base + sys_page_sz;
471 }
472
473 clib_mem_vm_map_hdr_t *
474 clib_mem_vm_get_next_map_hdr (clib_mem_vm_map_hdr_t * hdr)
475 {
476   clib_mem_main_t *mm = &clib_mem_main;
477   uword sys_page_sz = 1 << mm->log2_page_sz;
478   clib_mem_vm_map_hdr_t *next;
479   if (hdr == 0)
480     {
481       hdr = mm->first_map;
482       if (hdr)
483         mprotect (hdr, sys_page_sz, PROT_READ);
484       return hdr;
485     }
486   next = hdr->next;
487   mprotect (hdr, sys_page_sz, PROT_NONE);
488   if (next)
489     mprotect (next, sys_page_sz, PROT_READ);
490   return next;
491 }
492
493 void *
494 clib_mem_vm_map_internal (void *base, clib_mem_page_sz_t log2_page_sz,
495                           uword size, int fd, uword offset, char *name)
496 {
497   clib_mem_main_t *mm = &clib_mem_main;
498   clib_mem_vm_map_hdr_t *hdr;
499   uword sys_page_sz = 1 << mm->log2_page_sz;
500   int mmap_flags = MAP_FIXED, is_huge = 0;
501
502   if (fd != -1)
503     {
504       mmap_flags |= MAP_SHARED;
505       log2_page_sz = clib_mem_get_fd_log2_page_size (fd);
506       if (log2_page_sz > mm->log2_page_sz)
507         is_huge = 1;
508     }
509   else
510     {
511       mmap_flags |= MAP_PRIVATE | MAP_ANONYMOUS;
512
513       if (log2_page_sz == mm->log2_page_sz)
514         log2_page_sz = CLIB_MEM_PAGE_SZ_DEFAULT;
515
516       switch (log2_page_sz)
517         {
518         case CLIB_MEM_PAGE_SZ_UNKNOWN:
519           /* will fail later */
520           break;
521         case CLIB_MEM_PAGE_SZ_DEFAULT:
522           log2_page_sz = mm->log2_page_sz;
523           break;
524         case CLIB_MEM_PAGE_SZ_DEFAULT_HUGE:
525           mmap_flags |= MAP_HUGETLB;
526           log2_page_sz = mm->log2_default_hugepage_sz;
527           is_huge = 1;
528           break;
529         default:
530           mmap_flags |= MAP_HUGETLB;
531           mmap_flags |= log2_page_sz << MAP_HUGE_SHIFT;
532           is_huge = 1;
533         }
534     }
535
536   if (log2_page_sz == CLIB_MEM_PAGE_SZ_UNKNOWN)
537     return CLIB_MEM_VM_MAP_FAILED;
538
539   size = round_pow2 (size, 1 << log2_page_sz);
540
541   base = (void *) clib_mem_vm_reserve ((uword) base, size, log2_page_sz);
542
543   if (base == (void *) ~0)
544     return CLIB_MEM_VM_MAP_FAILED;
545
546   base = mmap (base, size, PROT_READ | PROT_WRITE, mmap_flags, fd, offset);
547
548   if (base == MAP_FAILED)
549     return CLIB_MEM_VM_MAP_FAILED;
550
551   if (is_huge && (mlock (base, size) != 0))
552     {
553       munmap (base, size);
554       return CLIB_MEM_VM_MAP_FAILED;
555     }
556
557   hdr = mmap (base - sys_page_sz, sys_page_sz, PROT_READ | PROT_WRITE,
558               MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0);
559
560   if (hdr != base - sys_page_sz)
561     {
562       munmap (base, size);
563       return CLIB_MEM_VM_MAP_FAILED;
564     }
565
566   if (mm->last_map)
567     {
568       mprotect (mm->last_map, sys_page_sz, PROT_READ | PROT_WRITE);
569       mm->last_map->next = hdr;
570       mprotect (mm->last_map, sys_page_sz, PROT_NONE);
571     }
572   else
573     mm->first_map = hdr;
574
575   hdr->next = 0;
576   hdr->prev = mm->last_map;
577   mm->last_map = hdr;
578
579   hdr->base_addr = (uword) base;
580   hdr->log2_page_sz = log2_page_sz;
581   hdr->num_pages = size >> log2_page_sz;
582   snprintf (hdr->name, CLIB_VM_MAP_HDR_NAME_MAX_LEN - 1, "%s", (char *) name);
583   hdr->name[CLIB_VM_MAP_HDR_NAME_MAX_LEN - 1] = 0;
584   mprotect (hdr, sys_page_sz, PROT_NONE);
585
586   CLIB_MEM_UNPOISON (base, size);
587   return base;
588 }
589
590 int
591 clib_mem_vm_unmap (void *base)
592 {
593   clib_mem_main_t *mm = &clib_mem_main;
594   uword size, sys_page_sz = 1 << mm->log2_page_sz;
595   clib_mem_vm_map_hdr_t *hdr = base - sys_page_sz;;
596
597   if (mprotect (hdr, sys_page_sz, PROT_READ | PROT_WRITE) != 0)
598     return -1;
599
600   size = hdr->num_pages << hdr->log2_page_sz;
601   if (munmap ((void *) hdr->base_addr, size) != 0)
602     return -1;
603
604   if (hdr->next)
605     {
606       mprotect (hdr->next, sys_page_sz, PROT_READ | PROT_WRITE);
607       hdr->next->prev = hdr->prev;
608       mprotect (hdr->next, sys_page_sz, PROT_NONE);
609     }
610   else
611     mm->last_map = hdr->prev;
612
613   if (hdr->prev)
614     {
615       mprotect (hdr->prev, sys_page_sz, PROT_READ | PROT_WRITE);
616       hdr->prev->next = hdr->next;
617       mprotect (hdr->prev, sys_page_sz, PROT_NONE);
618     }
619   else
620     mm->first_map = hdr->next;
621
622   if (munmap (hdr, sys_page_sz) != 0)
623     return -1;
624
625   return 0;
626 }
627
628 void
629 clib_mem_get_page_stats (void *start, clib_mem_page_sz_t log2_page_size,
630                          uword n_pages, clib_mem_page_stats_t * stats)
631 {
632   int i, *status = 0;
633   void **ptr = 0;
634
635   log2_page_size = clib_mem_log2_page_size_validate (log2_page_size);
636
637   vec_validate (status, n_pages - 1);
638   vec_validate (ptr, n_pages - 1);
639
640   for (i = 0; i < n_pages; i++)
641     ptr[i] = start + (i << log2_page_size);
642
643   clib_memset (stats, 0, sizeof (clib_mem_page_stats_t));
644
645   if (move_pages (0, n_pages, ptr, 0, status, 0) != 0)
646     {
647       stats->unknown = n_pages;
648       return;
649     }
650
651   for (i = 0; i < n_pages; i++)
652     {
653       if (status[i] >= 0 && status[i] < CLIB_MAX_NUMAS)
654         {
655           stats->mapped++;
656           stats->per_numa[status[i]]++;
657         }
658       else if (status[i] == -EFAULT)
659         stats->not_mapped++;
660       else
661         stats->unknown++;
662     }
663 }
664
665
666 u64 *
667 clib_mem_vm_get_paddr (void *mem, clib_mem_page_sz_t log2_page_size,
668                        int n_pages)
669 {
670   int pagesize = sysconf (_SC_PAGESIZE);
671   int fd;
672   int i;
673   u64 *r = 0;
674
675   log2_page_size = clib_mem_log2_page_size_validate (log2_page_size);
676
677   if ((fd = open ((char *) "/proc/self/pagemap", O_RDONLY)) == -1)
678     return 0;
679
680   for (i = 0; i < n_pages; i++)
681     {
682       u64 seek, pagemap = 0;
683       uword vaddr = pointer_to_uword (mem) + (((u64) i) << log2_page_size);
684       seek = ((u64) vaddr / pagesize) * sizeof (u64);
685       if (lseek (fd, seek, SEEK_SET) != seek)
686         goto done;
687
688       if (read (fd, &pagemap, sizeof (pagemap)) != (sizeof (pagemap)))
689         goto done;
690
691       if ((pagemap & (1ULL << 63)) == 0)
692         goto done;
693
694       pagemap &= pow2_mask (55);
695       vec_add1 (r, pagemap * pagesize);
696     }
697
698 done:
699   close (fd);
700   if (vec_len (r) != n_pages)
701     {
702       vec_free (r);
703       return 0;
704     }
705   return r;
706 }
707
708 clib_error_t *
709 clib_mem_vm_ext_map (clib_mem_vm_map_t * a)
710 {
711   long unsigned int old_mask[16] = { 0 };
712   int mmap_flags = MAP_SHARED;
713   clib_error_t *err = 0;
714   int old_mpol = -1;
715   void *addr;
716   int rv;
717
718   if (a->numa_node)
719     {
720       rv = get_mempolicy (&old_mpol, old_mask, sizeof (old_mask) * 8 + 1, 0,
721                           0);
722
723       if (rv == -1)
724         {
725           err = clib_error_return_unix (0, "get_mempolicy");
726           goto done;
727         }
728     }
729
730   if (a->requested_va)
731     mmap_flags |= MAP_FIXED;
732
733   if (old_mpol != -1)
734     {
735       long unsigned int mask[16] = { 0 };
736       mask[0] = 1 << a->numa_node;
737       rv = set_mempolicy (MPOL_BIND, mask, sizeof (mask) * 8 + 1);
738       if (rv == -1)
739         {
740           err = clib_error_return_unix (0, "set_mempolicy");
741           goto done;
742         }
743     }
744
745   addr = (void *) mmap (uword_to_pointer (a->requested_va, void *), a->size,
746                         PROT_READ | PROT_WRITE, mmap_flags, a->fd, 0);
747
748   if (addr == MAP_FAILED)
749     return clib_error_return_unix (0, "mmap");
750
751   /* re-apply old numa memory policy */
752   if (old_mpol != -1 &&
753       set_mempolicy (old_mpol, old_mask, sizeof (old_mask) * 8 + 1) == -1)
754     {
755       err = clib_error_return_unix (0, "set_mempolicy");
756       goto done;
757     }
758
759   a->addr = addr;
760   CLIB_MEM_UNPOISON (addr, a->size);
761
762 done:
763   return err;
764 }
765
766 /*
767  * fd.io coding-style-patch-verification: ON
768  *
769  * Local Variables:
770  * eval: (c-set-style "gnu")
771  * End:
772  */