Branch data Line data Source code
1 : : #include <stdio.h>
2 : : #include <stdbool.h>
3 : : #include <sys/mman.h>
4 : :
5 : : #include "rst-malloc.h"
6 : : #include "bug.h"
7 : : #include "asm/types.h"
8 : :
9 : : struct rst_mem_type_s {
10 : : bool remapable;
11 : : bool enabled;
12 : : unsigned long free_bytes;
13 : : void *free_mem;
14 : : int (*grow)(struct rst_mem_type_s *, unsigned long size);
15 : : unsigned long last;
16 : :
17 : : void *buf;
18 : : unsigned long size;
19 : : };
20 : :
21 : : #define RST_MEM_BATCH (2 * PAGE_SIZE)
22 : :
23 : 1521 : static inline unsigned long rst_mem_grow(unsigned long need_size)
24 : : {
25 : 1521 : need_size = round_up(need_size, PAGE_SIZE);
26 [ - + ]: 1521 : if (likely(need_size < RST_MEM_BATCH))
27 : : need_size = RST_MEM_BATCH;
28 : : else
29 : 0 : pr_debug("Growing rst memory %lu pages\n", need_size / PAGE_SIZE);
30 : 1521 : return need_size;
31 : : }
32 : :
33 : 1012 : static int grow_shared(struct rst_mem_type_s *t, unsigned long size)
34 : : {
35 : : void *aux;
36 : :
37 : 1012 : size = rst_mem_grow(size);
38 : :
39 : : /*
40 : : * This buffer will not get remapped into
41 : : * restorer, thus we can just forget the
42 : : * previous chunk location and allocate a
43 : : * new one
44 : : */
45 : 1012 : aux = mmap(NULL, size, PROT_READ | PROT_WRITE,
46 : : MAP_SHARED | MAP_ANON, 0, 0);
47 [ + - ]: 1012 : if (aux == MAP_FAILED)
48 : : return -1;
49 : :
50 : 1012 : t->free_mem = aux;
51 : 1012 : t->free_bytes = size;
52 : 1012 : t->last = 0;
53 : :
54 : 1012 : return 0;
55 : : }
56 : :
57 : 509 : static int grow_remap(struct rst_mem_type_s *t, int flag, unsigned long size)
58 : : {
59 : : void *aux;
60 : :
61 : 509 : size = rst_mem_grow(size);
62 : :
63 [ + + ]: 509 : if (!t->buf)
64 : : /*
65 : : * Can't call mremap with NULL address :(
66 : : */
67 : 373 : aux = mmap(NULL, size, PROT_READ | PROT_WRITE,
68 : : flag | MAP_ANON, 0, 0);
69 : : else
70 : : /*
71 : : * We'll have to remap all objects into restorer
72 : : * address space and get their new addresses. Since
73 : : * we allocate many objects as one linear array, it's
74 : : * simpler just to grow the buffer and let callers
75 : : * find out new array addresses, rather than allocate
76 : : * a completely new one and force callers use objects'
77 : : * cpos-s.
78 : : */
79 : 136 : aux = mremap(t->buf, t->size,
80 : 136 : t->size + size, MREMAP_MAYMOVE);
81 [ + - ]: 509 : if (aux == MAP_FAILED)
82 : : return -1;
83 : :
84 : 509 : t->free_mem += (aux - t->buf);
85 : 509 : t->free_bytes += size;
86 : 509 : t->size += size;
87 : 509 : t->buf = aux;
88 : :
89 : 509 : return 0;
90 : : }
91 : :
92 : 26 : static int grow_shremap(struct rst_mem_type_s *t, unsigned long size)
93 : : {
94 : 26 : return grow_remap(t, MAP_SHARED, size);
95 : : }
96 : :
97 : 483 : static int grow_private(struct rst_mem_type_s *t, unsigned long size)
98 : : {
99 : 483 : return grow_remap(t, MAP_PRIVATE, size);
100 : : }
101 : :
102 : : static struct rst_mem_type_s rst_mems[RST_MEM_TYPES] = {
103 : : [RM_SHARED] = {
104 : : .grow = grow_shared,
105 : : .remapable = false,
106 : : .enabled = true,
107 : : },
108 : : [RM_SHREMAP] = {
109 : : .grow = grow_shremap,
110 : : .remapable = true,
111 : : .enabled = true,
112 : : },
113 : : [RM_PRIVATE] = {
114 : : .grow = grow_private,
115 : : .remapable = true,
116 : : .enabled = false,
117 : : },
118 : : };
119 : :
120 : 347 : void rst_mem_switch_to_private(void)
121 : : {
122 : 347 : rst_mems[RM_SHARED].enabled = false;
123 : 347 : rst_mems[RM_SHREMAP].enabled = false;
124 : 347 : rst_mems[RM_PRIVATE].enabled = true;
125 : 347 : }
126 : :
127 : 1735 : unsigned long rst_mem_cpos(int type)
128 : : {
129 : 1735 : struct rst_mem_type_s *t = &rst_mems[type];
130 [ + - ][ - + ]: 1735 : BUG_ON(!t->remapable || !t->enabled);
131 : 1735 : return t->free_mem - t->buf;
132 : : }
133 : :
134 : 3132 : void *rst_mem_remap_ptr(unsigned long pos, int type)
135 : : {
136 : 3132 : struct rst_mem_type_s *t = &rst_mems[type];
137 [ - + ]: 3132 : BUG_ON(!t->remapable);
138 : 3132 : return t->buf + pos;
139 : : }
140 : :
141 : 34309 : void *rst_mem_alloc(unsigned long size, int type)
142 : : {
143 : 34309 : struct rst_mem_type_s *t = &rst_mems[type];
144 : : void *ret;
145 : :
146 [ - + ]: 34309 : BUG_ON(!t->enabled);
147 : :
148 [ + + ][ - + ]: 34309 : if ((t->free_bytes < size) && t->grow(t, size)) {
149 : 0 : pr_perror("Can't grow rst mem");
150 : 0 : return NULL;
151 : : }
152 : :
153 : 34309 : ret = t->free_mem;
154 : 34309 : t->free_mem += size;
155 : 34309 : t->free_bytes -= size;
156 : 34309 : t->last = size;
157 : :
158 : 34309 : return ret;
159 : : }
160 : :
161 : 354 : void rst_mem_free_last(int type)
162 : : {
163 : 354 : struct rst_mem_type_s *t = &rst_mems[type];
164 : :
165 [ - + ]: 354 : BUG_ON(!t->enabled);
166 : :
167 : 354 : t->free_mem -= t->last;
168 : 354 : t->free_bytes += t->last;
169 : 354 : t->last = 0; /* next free_last would be no-op */
170 : 354 : }
171 : :
172 : 1041 : unsigned long rst_mem_remap_size(void)
173 : : {
174 : 1041 : return rst_mems[RM_PRIVATE].size + rst_mems[RM_SHREMAP].size;
175 : : }
176 : :
177 : 694 : static int rst_mem_remap_one(struct rst_mem_type_s *t, void *to)
178 : : {
179 : : void *aux;
180 : :
181 [ - + ]: 694 : BUG_ON(!t->remapable);
182 : :
183 [ + + ]: 694 : if (!t->buf)
184 : : /*
185 : : * No allocations happenned from this buffer.
186 : : * It's safe just to do nothing.
187 : : */
188 : : return 0;
189 : :
190 : 373 : pr_debug("\tcall mremap(%p, %lu, %lu, MAYMOVE | FIXED, %p)\n",
191 : : t->buf, t->size, t->size, to);
192 : 373 : aux = mremap(t->buf, t->size, t->size, MREMAP_MAYMOVE | MREMAP_FIXED, to);
193 [ - + ]: 373 : if (aux == MAP_FAILED) {
194 : 0 : pr_perror("Can't mremap rst mem");
195 : 0 : return -1;
196 : : }
197 : :
198 : 373 : t->buf = aux;
199 : 373 : t->enabled = false;
200 : 373 : return 0;
201 : : }
202 : :
203 : 347 : int rst_mem_remap(void *to)
204 : : {
205 : : int ret;
206 : :
207 : 347 : ret = rst_mem_remap_one(&rst_mems[RM_PRIVATE], to);
208 [ + - ]: 347 : if (!ret) {
209 : 347 : to += rst_mems[RM_PRIVATE].size;
210 : 347 : ret = rst_mem_remap_one(&rst_mems[RM_SHREMAP], to);
211 : : }
212 : :
213 : 347 : return ret;
214 : : }
|