]>
Commit | Line | Data |
---|---|---|
a4b75251 TL |
1 | // SPDX-License-Identifier: BSD-3-Clause |
2 | /* Copyright 2020, Intel Corporation */ | |
3 | ||
4 | /* | |
5 | * vm_reservation_posix.c -- implementation of virtual memory | |
6 | * reservation API (POSIX) | |
7 | */ | |
8 | ||
9 | #include <sys/mman.h> | |
10 | ||
11 | #include "alloc.h" | |
12 | #include "map.h" | |
13 | #include "out.h" | |
14 | #include "pmem2_utils.h" | |
15 | ||
16 | int vm_reservation_reserve_memory(void *addr, size_t size, void **raddr, | |
17 | size_t *rsize); | |
18 | int vm_reservation_release_memory(void *addr, size_t size); | |
19 | ||
20 | /* | |
21 | * vm_reservation_reserve_memory -- create a blank virual memory mapping | |
22 | */ | |
23 | int | |
24 | vm_reservation_reserve_memory(void *addr, size_t size, void **raddr, | |
25 | size_t *rsize) | |
26 | { | |
27 | int map_flag = 0; | |
28 | if (addr) { | |
29 | /* | |
30 | * glibc started exposing MAP_FIXED_NOREPLACE flag in version 4.17, | |
31 | * but even if the flag is not supported, we can imitate its behavior | |
32 | */ | |
33 | #ifdef MAP_FIXED_NOREPLACE | |
34 | map_flag = MAP_FIXED_NOREPLACE; | |
35 | #endif | |
36 | } | |
37 | ||
38 | /* | |
39 | * Create a dummy mapping to find an unused region of given size. | |
40 | * If the flag is supported and requested region is occupied, | |
41 | * mmap will fail with EEXIST. | |
42 | */ | |
43 | char *daddr = mmap(addr, size, PROT_NONE, | |
44 | MAP_PRIVATE | MAP_ANONYMOUS | map_flag, -1, 0); | |
45 | if (daddr == MAP_FAILED) { | |
46 | if (errno == EEXIST) { | |
47 | ERR("!mmap MAP_FIXED_NOREPLACE"); | |
48 | return PMEM2_E_MAPPING_EXISTS; | |
49 | } | |
50 | ERR("!mmap MAP_ANONYMOUS"); | |
51 | return PMEM2_E_ERRNO; | |
52 | } | |
53 | ||
54 | /* | |
55 | * When requested address is not specified, any returned address | |
56 | * is acceptable. If kernel does not support flag and given addr | |
57 | * is occupied, kernel chooses new addr randomly and returns it. | |
58 | * We do not want that behavior, so we validate it and fail when | |
59 | * addresses do not match. | |
60 | */ | |
61 | if (addr && daddr != addr) { | |
62 | munmap(daddr, size); | |
63 | ERR("mapping exists in the given address"); | |
64 | return PMEM2_E_MAPPING_EXISTS; | |
65 | } | |
66 | ||
67 | *raddr = daddr; | |
68 | *rsize = roundup(size, Pagesize); | |
69 | ||
70 | return 0; | |
71 | } | |
72 | ||
73 | /* | |
74 | * vm_reservation_release_memory -- releases blank virtual memory mapping | |
75 | */ | |
76 | int | |
77 | vm_reservation_release_memory(void *addr, size_t size) | |
78 | { | |
79 | if (munmap(addr, size)) { | |
80 | ERR("!munmap"); | |
81 | return PMEM2_E_ERRNO; | |
82 | } | |
83 | ||
84 | return 0; | |
85 | } |