File: | build-scan/../src/journal/mmap-cache.c |
Warning: | line 682, column 17 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* SPDX-License-Identifier: LGPL-2.1+ */ | |||
2 | ||||
3 | #include <errno(*__errno_location ()).h> | |||
4 | #include <stdlib.h> | |||
5 | #include <sys/mman.h> | |||
6 | ||||
7 | #include "alloc-util.h" | |||
8 | #include "fd-util.h" | |||
9 | #include "hashmap.h" | |||
10 | #include "list.h" | |||
11 | #include "log.h" | |||
12 | #include "macro.h" | |||
13 | #include "mmap-cache.h" | |||
14 | #include "sigbus.h" | |||
15 | #include "util.h" | |||
16 | ||||
17 | typedef struct Window Window; | |||
18 | typedef struct Context Context; | |||
19 | ||||
20 | struct Window { | |||
21 | MMapCache *cache; | |||
22 | ||||
23 | bool_Bool invalidated:1; | |||
24 | bool_Bool keep_always:1; | |||
25 | bool_Bool in_unused:1; | |||
26 | ||||
27 | int prot; | |||
28 | void *ptr; | |||
29 | uint64_t offset; | |||
30 | size_t size; | |||
31 | ||||
32 | MMapFileDescriptor *fd; | |||
33 | ||||
34 | LIST_FIELDS(Window, by_fd)Window *by_fd_next, *by_fd_prev; | |||
35 | LIST_FIELDS(Window, unused)Window *unused_next, *unused_prev; | |||
36 | ||||
37 | LIST_HEAD(Context, contexts)Context *contexts; | |||
38 | }; | |||
39 | ||||
40 | struct Context { | |||
41 | MMapCache *cache; | |||
42 | unsigned id; | |||
43 | Window *window; | |||
44 | ||||
45 | LIST_FIELDS(Context, by_window)Context *by_window_next, *by_window_prev; | |||
46 | }; | |||
47 | ||||
48 | struct MMapFileDescriptor { | |||
49 | MMapCache *cache; | |||
50 | int fd; | |||
51 | bool_Bool sigbus; | |||
52 | LIST_HEAD(Window, windows)Window *windows; | |||
53 | }; | |||
54 | ||||
55 | struct MMapCache { | |||
56 | int n_ref; | |||
57 | unsigned n_windows; | |||
58 | ||||
59 | unsigned n_hit, n_missed; | |||
60 | ||||
61 | Hashmap *fds; | |||
62 | Context *contexts[MMAP_CACHE_MAX_CONTEXTS9]; | |||
63 | ||||
64 | LIST_HEAD(Window, unused)Window *unused; | |||
65 | Window *last_unused; | |||
66 | }; | |||
67 | ||||
68 | #define WINDOWS_MIN64 64 | |||
69 | ||||
70 | #if ENABLE_DEBUG_MMAP_CACHE0 | |||
71 | /* Tiny windows increase mmap activity and the chance of exposing unsafe use. */ | |||
72 | # define WINDOW_SIZE(8ULL*1024ULL*1024ULL) (page_size()) | |||
73 | #else | |||
74 | # define WINDOW_SIZE(8ULL*1024ULL*1024ULL) (8ULL*1024ULL*1024ULL) | |||
75 | #endif | |||
76 | ||||
77 | MMapCache* mmap_cache_new(void) { | |||
78 | MMapCache *m; | |||
79 | ||||
80 | m = new0(MMapCache, 1)((MMapCache*) calloc((1), sizeof(MMapCache))); | |||
81 | if (!m) | |||
82 | return NULL((void*)0); | |||
83 | ||||
84 | m->n_ref = 1; | |||
85 | return m; | |||
86 | } | |||
87 | ||||
88 | MMapCache* mmap_cache_ref(MMapCache *m) { | |||
89 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 89, __PRETTY_FUNCTION__); } while (0); | |||
90 | assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c" , 90, __PRETTY_FUNCTION__); } while (0); | |||
91 | ||||
92 | m->n_ref++; | |||
93 | return m; | |||
94 | } | |||
95 | ||||
96 | static void window_unlink(Window *w) { | |||
97 | Context *c; | |||
98 | ||||
99 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 99, __PRETTY_FUNCTION__); } while (0); | |||
100 | ||||
101 | if (w->ptr) | |||
102 | munmap(w->ptr, w->size); | |||
103 | ||||
104 | if (w->fd) | |||
105 | LIST_REMOVE(by_fd, w->fd->windows, w)do { typeof(*(w->fd->windows)) **_head = &(w->fd ->windows), *_item = (w); do { if ((__builtin_expect(!!(!( _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item" ), "../src/journal/mmap-cache.c", 105, __PRETTY_FUNCTION__); } while (0); if (_item->by_fd_next) _item->by_fd_next-> by_fd_prev = _item->by_fd_prev; if (_item->by_fd_prev) _item ->by_fd_prev->by_fd_next = _item->by_fd_next; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("*_head == _item"), "../src/journal/mmap-cache.c" , 105, __PRETTY_FUNCTION__); } while (0); *_head = _item-> by_fd_next; } _item->by_fd_next = _item->by_fd_prev = ( (void*)0); } while (0); | |||
106 | ||||
107 | if (w->in_unused) { | |||
108 | if (w->cache->last_unused == w) | |||
109 | w->cache->last_unused = w->unused_prev; | |||
110 | ||||
111 | LIST_REMOVE(unused, w->cache->unused, w)do { typeof(*(w->cache->unused)) **_head = &(w-> cache->unused), *_item = (w); do { if ((__builtin_expect(! !(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ( "_item"), "../src/journal/mmap-cache.c", 111, __PRETTY_FUNCTION__ ); } while (0); if (_item->unused_next) _item->unused_next ->unused_prev = _item->unused_prev; if (_item->unused_prev ) _item->unused_prev->unused_next = _item->unused_next ; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item" ), "../src/journal/mmap-cache.c", 111, __PRETTY_FUNCTION__); } while (0); *_head = _item->unused_next; } _item->unused_next = _item->unused_prev = ((void*)0); } while (0); | |||
112 | } | |||
113 | ||||
114 | LIST_FOREACH(by_window, c, w->contexts)for ((c) = (w->contexts); (c); (c) = (c)->by_window_next ) { | |||
115 | assert(c->window == w)do { if ((__builtin_expect(!!(!(c->window == w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c->window == w"), "../src/journal/mmap-cache.c" , 115, __PRETTY_FUNCTION__); } while (0); | |||
116 | c->window = NULL((void*)0); | |||
117 | } | |||
118 | } | |||
119 | ||||
120 | static void window_invalidate(Window *w) { | |||
121 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 121 , __PRETTY_FUNCTION__); } while (0); | |||
122 | ||||
123 | if (w->invalidated) | |||
124 | return; | |||
125 | ||||
126 | /* Replace the window with anonymous pages. This is useful | |||
127 | * when we hit a SIGBUS and want to make sure the file cannot | |||
128 | * trigger any further SIGBUS, possibly overrunning the sigbus | |||
129 | * queue. */ | |||
130 | ||||
131 | assert_se(mmap(w->ptr, w->size, w->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr)do { if ((__builtin_expect(!!(!(mmap(w->ptr, w->size, w ->prot, 0x02|0x20|0x10, -1, 0) == w->ptr)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("mmap(w->ptr, w->size, w->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr" ), "../src/journal/mmap-cache.c", 131, __PRETTY_FUNCTION__); } while (0); | |||
132 | w->invalidated = true1; | |||
133 | } | |||
134 | ||||
135 | static void window_free(Window *w) { | |||
136 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 136 , __PRETTY_FUNCTION__); } while (0); | |||
137 | ||||
138 | window_unlink(w); | |||
139 | w->cache->n_windows--; | |||
140 | free(w); | |||
141 | } | |||
142 | ||||
143 | _pure___attribute__ ((pure)) static inline bool_Bool window_matches(Window *w, int prot, uint64_t offset, size_t size) { | |||
144 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 144 , __PRETTY_FUNCTION__); } while (0); | |||
145 | assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c" , 145, __PRETTY_FUNCTION__); } while (0); | |||
146 | ||||
147 | return | |||
148 | prot == w->prot && | |||
149 | offset >= w->offset && | |||
150 | offset + size <= w->offset + w->size; | |||
151 | } | |||
152 | ||||
153 | _pure___attribute__ ((pure)) static bool_Bool window_matches_fd(Window *w, MMapFileDescriptor *f, int prot, uint64_t offset, size_t size) { | |||
154 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 154 , __PRETTY_FUNCTION__); } while (0); | |||
155 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 155 , __PRETTY_FUNCTION__); } while (0); | |||
156 | ||||
157 | return | |||
158 | w->fd && | |||
159 | f->fd == w->fd->fd && | |||
160 | window_matches(w, prot, offset, size); | |||
161 | } | |||
162 | ||||
163 | static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool_Bool keep_always, uint64_t offset, size_t size, void *ptr) { | |||
164 | Window *w; | |||
165 | ||||
166 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 166 , __PRETTY_FUNCTION__); } while (0); | |||
167 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 167 , __PRETTY_FUNCTION__); } while (0); | |||
168 | ||||
169 | if (!m->last_unused || m->n_windows <= WINDOWS_MIN64) { | |||
170 | ||||
171 | /* Allocate a new window */ | |||
172 | w = new0(Window, 1)((Window*) calloc((1), sizeof(Window))); | |||
173 | if (!w) | |||
174 | return NULL((void*)0); | |||
175 | m->n_windows++; | |||
176 | } else { | |||
177 | ||||
178 | /* Reuse an existing one */ | |||
179 | w = m->last_unused; | |||
180 | window_unlink(w); | |||
181 | zero(*w)(({ size_t _l_ = (sizeof(*w)); void *_x_ = (&(*w)); _l_ == 0 ? _x_ : memset(_x_, 0, _l_); })); | |||
182 | } | |||
183 | ||||
184 | w->cache = m; | |||
185 | w->fd = f; | |||
186 | w->prot = prot; | |||
187 | w->keep_always = keep_always; | |||
188 | w->offset = offset; | |||
189 | w->size = size; | |||
190 | w->ptr = ptr; | |||
191 | ||||
192 | LIST_PREPEND(by_fd, f->windows, w)do { typeof(*(f->windows)) **_head = &(f->windows), *_item = (w); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("_item"), "../src/journal/mmap-cache.c", 192, __PRETTY_FUNCTION__); } while (0); if ((_item->by_fd_next = *_head)) _item->by_fd_next->by_fd_prev = _item; _item ->by_fd_prev = ((void*)0); *_head = _item; } while (0); | |||
193 | ||||
194 | return w; | |||
195 | } | |||
196 | ||||
197 | static void context_detach_window(Context *c) { | |||
198 | Window *w; | |||
199 | ||||
200 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/journal/mmap-cache.c", 200 , __PRETTY_FUNCTION__); } while (0); | |||
201 | ||||
202 | if (!c->window) | |||
203 | return; | |||
204 | ||||
205 | w = TAKE_PTR(c->window)({ typeof(c->window) _ptr_ = (c->window); (c->window ) = ((void*)0); _ptr_; }); | |||
206 | LIST_REMOVE(by_window, w->contexts, c)do { typeof(*(w->contexts)) **_head = &(w->contexts ), *_item = (c); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/journal/mmap-cache.c" , 206, __PRETTY_FUNCTION__); } while (0); if (_item->by_window_next ) _item->by_window_next->by_window_prev = _item->by_window_prev ; if (_item->by_window_prev) _item->by_window_prev-> by_window_next = _item->by_window_next; else { do { if ((__builtin_expect (!!(!(*_head == _item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD , ("*_head == _item"), "../src/journal/mmap-cache.c", 206, __PRETTY_FUNCTION__ ); } while (0); *_head = _item->by_window_next; } _item-> by_window_next = _item->by_window_prev = ((void*)0); } while (0); | |||
207 | ||||
208 | if (!w->contexts && !w->keep_always) { | |||
209 | /* Not used anymore? */ | |||
210 | #if ENABLE_DEBUG_MMAP_CACHE0 | |||
211 | /* Unmap unused windows immediately to expose use-after-unmap | |||
212 | * by SIGSEGV. */ | |||
213 | window_free(w); | |||
214 | #else | |||
215 | LIST_PREPEND(unused, c->cache->unused, w)do { typeof(*(c->cache->unused)) **_head = &(c-> cache->unused), *_item = (w); do { if ((__builtin_expect(! !(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ( "_item"), "../src/journal/mmap-cache.c", 215, __PRETTY_FUNCTION__ ); } while (0); if ((_item->unused_next = *_head)) _item-> unused_next->unused_prev = _item; _item->unused_prev = ( (void*)0); *_head = _item; } while (0); | |||
216 | if (!c->cache->last_unused) | |||
217 | c->cache->last_unused = w; | |||
218 | ||||
219 | w->in_unused = true1; | |||
220 | #endif | |||
221 | } | |||
222 | } | |||
223 | ||||
224 | static void context_attach_window(Context *c, Window *w) { | |||
225 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/journal/mmap-cache.c", 225 , __PRETTY_FUNCTION__); } while (0); | |||
226 | assert(w)do { if ((__builtin_expect(!!(!(w)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("w"), "../src/journal/mmap-cache.c", 226 , __PRETTY_FUNCTION__); } while (0); | |||
227 | ||||
228 | if (c->window == w) | |||
229 | return; | |||
230 | ||||
231 | context_detach_window(c); | |||
232 | ||||
233 | if (w->in_unused) { | |||
234 | /* Used again? */ | |||
235 | LIST_REMOVE(unused, c->cache->unused, w)do { typeof(*(c->cache->unused)) **_head = &(c-> cache->unused), *_item = (w); do { if ((__builtin_expect(! !(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ( "_item"), "../src/journal/mmap-cache.c", 235, __PRETTY_FUNCTION__ ); } while (0); if (_item->unused_next) _item->unused_next ->unused_prev = _item->unused_prev; if (_item->unused_prev ) _item->unused_prev->unused_next = _item->unused_next ; else { do { if ((__builtin_expect(!!(!(*_head == _item)),0) )) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("*_head == _item" ), "../src/journal/mmap-cache.c", 235, __PRETTY_FUNCTION__); } while (0); *_head = _item->unused_next; } _item->unused_next = _item->unused_prev = ((void*)0); } while (0); | |||
236 | if (c->cache->last_unused == w) | |||
237 | c->cache->last_unused = w->unused_prev; | |||
238 | ||||
239 | w->in_unused = false0; | |||
240 | } | |||
241 | ||||
242 | c->window = w; | |||
243 | LIST_PREPEND(by_window, w->contexts, c)do { typeof(*(w->contexts)) **_head = &(w->contexts ), *_item = (c); do { if ((__builtin_expect(!!(!(_item)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("_item"), "../src/journal/mmap-cache.c" , 243, __PRETTY_FUNCTION__); } while (0); if ((_item->by_window_next = *_head)) _item->by_window_next->by_window_prev = _item ; _item->by_window_prev = ((void*)0); *_head = _item; } while (0); | |||
244 | } | |||
245 | ||||
246 | static Context *context_add(MMapCache *m, unsigned id) { | |||
247 | Context *c; | |||
248 | ||||
249 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 249 , __PRETTY_FUNCTION__); } while (0); | |||
250 | ||||
251 | c = m->contexts[id]; | |||
252 | if (c) | |||
253 | return c; | |||
254 | ||||
255 | c = new0(Context, 1)((Context*) calloc((1), sizeof(Context))); | |||
256 | if (!c) | |||
257 | return NULL((void*)0); | |||
258 | ||||
259 | c->cache = m; | |||
260 | c->id = id; | |||
261 | ||||
262 | assert(!m->contexts[id])do { if ((__builtin_expect(!!(!(!m->contexts[id])),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("!m->contexts[id]"), "../src/journal/mmap-cache.c" , 262, __PRETTY_FUNCTION__); } while (0); | |||
263 | m->contexts[id] = c; | |||
264 | ||||
265 | return c; | |||
266 | } | |||
267 | ||||
268 | static void context_free(Context *c) { | |||
269 | assert(c)do { if ((__builtin_expect(!!(!(c)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c"), "../src/journal/mmap-cache.c", 269 , __PRETTY_FUNCTION__); } while (0); | |||
270 | ||||
271 | context_detach_window(c); | |||
272 | ||||
273 | if (c->cache) { | |||
274 | assert(c->cache->contexts[c->id] == c)do { if ((__builtin_expect(!!(!(c->cache->contexts[c-> id] == c)),0))) log_assert_failed_realm(LOG_REALM_SYSTEMD, ("c->cache->contexts[c->id] == c" ), "../src/journal/mmap-cache.c", 274, __PRETTY_FUNCTION__); } while (0); | |||
275 | c->cache->contexts[c->id] = NULL((void*)0); | |||
276 | } | |||
277 | ||||
278 | free(c); | |||
279 | } | |||
280 | ||||
281 | static void mmap_cache_free(MMapCache *m) { | |||
282 | int i; | |||
283 | ||||
284 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 284 , __PRETTY_FUNCTION__); } while (0); | |||
285 | ||||
286 | for (i = 0; i < MMAP_CACHE_MAX_CONTEXTS9; i++) | |||
287 | if (m->contexts[i]) | |||
288 | context_free(m->contexts[i]); | |||
289 | ||||
290 | hashmap_free(m->fds); | |||
291 | ||||
292 | while (m->unused) | |||
293 | window_free(m->unused); | |||
294 | ||||
295 | free(m); | |||
296 | } | |||
297 | ||||
298 | MMapCache* mmap_cache_unref(MMapCache *m) { | |||
299 | ||||
300 | if (!m) | |||
301 | return NULL((void*)0); | |||
302 | ||||
303 | assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c" , 303, __PRETTY_FUNCTION__); } while (0); | |||
304 | ||||
305 | m->n_ref--; | |||
306 | if (m->n_ref == 0) | |||
307 | mmap_cache_free(m); | |||
308 | ||||
309 | return NULL((void*)0); | |||
310 | } | |||
311 | ||||
312 | static int make_room(MMapCache *m) { | |||
313 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 313 , __PRETTY_FUNCTION__); } while (0); | |||
314 | ||||
315 | if (!m->last_unused) | |||
316 | return 0; | |||
317 | ||||
318 | window_free(m->last_unused); | |||
319 | return 1; | |||
320 | } | |||
321 | ||||
322 | static int try_context( | |||
323 | MMapCache *m, | |||
324 | MMapFileDescriptor *f, | |||
325 | int prot, | |||
326 | unsigned context, | |||
327 | bool_Bool keep_always, | |||
328 | uint64_t offset, | |||
329 | size_t size, | |||
330 | void **ret, | |||
331 | size_t *ret_size) { | |||
332 | ||||
333 | Context *c; | |||
334 | ||||
335 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 335 , __PRETTY_FUNCTION__); } while (0); | |||
336 | assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c" , 336, __PRETTY_FUNCTION__); } while (0); | |||
337 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 337 , __PRETTY_FUNCTION__); } while (0); | |||
338 | assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c" , 338, __PRETTY_FUNCTION__); } while (0); | |||
339 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/journal/mmap-cache.c", 339 , __PRETTY_FUNCTION__); } while (0); | |||
340 | ||||
341 | c = m->contexts[context]; | |||
342 | if (!c) | |||
343 | return 0; | |||
344 | ||||
345 | assert(c->id == context)do { if ((__builtin_expect(!!(!(c->id == context)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("c->id == context"), "../src/journal/mmap-cache.c" , 345, __PRETTY_FUNCTION__); } while (0); | |||
346 | ||||
347 | if (!c->window) | |||
348 | return 0; | |||
349 | ||||
350 | if (!window_matches_fd(c->window, f, prot, offset, size)) { | |||
351 | ||||
352 | /* Drop the reference to the window, since it's unnecessary now */ | |||
353 | context_detach_window(c); | |||
354 | return 0; | |||
355 | } | |||
356 | ||||
357 | if (c->window->fd->sigbus) | |||
358 | return -EIO5; | |||
359 | ||||
360 | c->window->keep_always = c->window->keep_always || keep_always; | |||
361 | ||||
362 | *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); | |||
363 | if (ret_size) | |||
364 | *ret_size = c->window->size - (offset - c->window->offset); | |||
365 | ||||
366 | return 1; | |||
367 | } | |||
368 | ||||
369 | static int find_mmap( | |||
370 | MMapCache *m, | |||
371 | MMapFileDescriptor *f, | |||
372 | int prot, | |||
373 | unsigned context, | |||
374 | bool_Bool keep_always, | |||
375 | uint64_t offset, | |||
376 | size_t size, | |||
377 | void **ret, | |||
378 | size_t *ret_size) { | |||
379 | ||||
380 | Window *w; | |||
381 | Context *c; | |||
382 | ||||
383 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 383 , __PRETTY_FUNCTION__); } while (0); | |||
384 | assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c" , 384, __PRETTY_FUNCTION__); } while (0); | |||
385 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 385 , __PRETTY_FUNCTION__); } while (0); | |||
386 | assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c" , 386, __PRETTY_FUNCTION__); } while (0); | |||
387 | ||||
388 | if (f->sigbus) | |||
389 | return -EIO5; | |||
390 | ||||
391 | LIST_FOREACH(by_fd, w, f->windows)for ((w) = (f->windows); (w); (w) = (w)->by_fd_next) | |||
392 | if (window_matches(w, prot, offset, size)) | |||
393 | break; | |||
394 | ||||
395 | if (!w) | |||
396 | return 0; | |||
397 | ||||
398 | c = context_add(m, context); | |||
399 | if (!c) | |||
400 | return -ENOMEM12; | |||
401 | ||||
402 | context_attach_window(c, w); | |||
403 | w->keep_always = w->keep_always || keep_always; | |||
404 | ||||
405 | *ret = (uint8_t*) w->ptr + (offset - w->offset); | |||
406 | if (ret_size) | |||
407 | *ret_size = w->size - (offset - w->offset); | |||
408 | ||||
409 | return 1; | |||
410 | } | |||
411 | ||||
412 | static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int prot, int flags, uint64_t offset, size_t size, void **res) { | |||
413 | void *ptr; | |||
414 | ||||
415 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 415 , __PRETTY_FUNCTION__); } while (0); | |||
416 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 416 , __PRETTY_FUNCTION__); } while (0); | |||
417 | assert(res)do { if ((__builtin_expect(!!(!(res)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("res"), "../src/journal/mmap-cache.c", 417 , __PRETTY_FUNCTION__); } while (0); | |||
418 | ||||
419 | for (;;) { | |||
420 | int r; | |||
421 | ||||
422 | ptr = mmap(addr, size, prot, flags, f->fd, offset); | |||
423 | if (ptr != MAP_FAILED((void *) -1)) | |||
424 | break; | |||
425 | if (errno(*__errno_location ()) != ENOMEM12) | |||
426 | return negative_errno(); | |||
427 | ||||
428 | r = make_room(m); | |||
429 | if (r < 0) | |||
430 | return r; | |||
431 | if (r == 0) | |||
432 | return -ENOMEM12; | |||
433 | } | |||
434 | ||||
435 | *res = ptr; | |||
436 | return 0; | |||
437 | } | |||
438 | ||||
439 | static int add_mmap( | |||
440 | MMapCache *m, | |||
441 | MMapFileDescriptor *f, | |||
442 | int prot, | |||
443 | unsigned context, | |||
444 | bool_Bool keep_always, | |||
445 | uint64_t offset, | |||
446 | size_t size, | |||
447 | struct stat *st, | |||
448 | void **ret, | |||
449 | size_t *ret_size) { | |||
450 | ||||
451 | uint64_t woffset, wsize; | |||
452 | Context *c; | |||
453 | Window *w; | |||
454 | void *d; | |||
455 | int r; | |||
456 | ||||
457 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 457 , __PRETTY_FUNCTION__); } while (0); | |||
458 | assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c" , 458, __PRETTY_FUNCTION__); } while (0); | |||
459 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 459 , __PRETTY_FUNCTION__); } while (0); | |||
460 | assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c" , 460, __PRETTY_FUNCTION__); } while (0); | |||
461 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/journal/mmap-cache.c", 461 , __PRETTY_FUNCTION__); } while (0); | |||
462 | ||||
463 | woffset = offset & ~((uint64_t) page_size() - 1ULL); | |||
464 | wsize = size + (offset - woffset); | |||
465 | wsize = PAGE_ALIGN(wsize)ALIGN_TO((wsize), page_size()); | |||
466 | ||||
467 | if (wsize < WINDOW_SIZE(8ULL*1024ULL*1024ULL)) { | |||
468 | uint64_t delta; | |||
469 | ||||
470 | delta = PAGE_ALIGN((WINDOW_SIZE - wsize) / 2)ALIGN_TO((((8ULL*1024ULL*1024ULL) - wsize) / 2), page_size()); | |||
471 | ||||
472 | if (delta > offset) | |||
473 | woffset = 0; | |||
474 | else | |||
475 | woffset -= delta; | |||
476 | ||||
477 | wsize = WINDOW_SIZE(8ULL*1024ULL*1024ULL); | |||
478 | } | |||
479 | ||||
480 | if (st) { | |||
481 | /* Memory maps that are larger then the files | |||
482 | underneath have undefined behavior. Hence, clamp | |||
483 | things to the file size if we know it */ | |||
484 | ||||
485 | if (woffset >= (uint64_t) st->st_size) | |||
486 | return -EADDRNOTAVAIL99; | |||
487 | ||||
488 | if (woffset + wsize > (uint64_t) st->st_size) | |||
489 | wsize = PAGE_ALIGN(st->st_size - woffset)ALIGN_TO((st->st_size - woffset), page_size()); | |||
490 | } | |||
491 | ||||
492 | r = mmap_try_harder(m, NULL((void*)0), f, prot, MAP_SHARED0x01, woffset, wsize, &d); | |||
493 | if (r < 0) | |||
494 | return r; | |||
495 | ||||
496 | c = context_add(m, context); | |||
497 | if (!c) | |||
498 | goto outofmem; | |||
499 | ||||
500 | w = window_add(m, f, prot, keep_always, woffset, wsize, d); | |||
501 | if (!w) | |||
502 | goto outofmem; | |||
503 | ||||
504 | context_attach_window(c, w); | |||
505 | ||||
506 | *ret = (uint8_t*) w->ptr + (offset - w->offset); | |||
507 | if (ret_size) | |||
508 | *ret_size = w->size - (offset - w->offset); | |||
509 | ||||
510 | return 1; | |||
511 | ||||
512 | outofmem: | |||
513 | (void) munmap(d, wsize); | |||
514 | return -ENOMEM12; | |||
515 | } | |||
516 | ||||
517 | int mmap_cache_get( | |||
518 | MMapCache *m, | |||
519 | MMapFileDescriptor *f, | |||
520 | int prot, | |||
521 | unsigned context, | |||
522 | bool_Bool keep_always, | |||
523 | uint64_t offset, | |||
524 | size_t size, | |||
525 | struct stat *st, | |||
526 | void **ret, | |||
527 | size_t *ret_size) { | |||
528 | ||||
529 | int r; | |||
530 | ||||
531 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 531 , __PRETTY_FUNCTION__); } while (0); | |||
532 | assert(m->n_ref > 0)do { if ((__builtin_expect(!!(!(m->n_ref > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m->n_ref > 0"), "../src/journal/mmap-cache.c" , 532, __PRETTY_FUNCTION__); } while (0); | |||
533 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 533 , __PRETTY_FUNCTION__); } while (0); | |||
534 | assert(size > 0)do { if ((__builtin_expect(!!(!(size > 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("size > 0"), "../src/journal/mmap-cache.c" , 534, __PRETTY_FUNCTION__); } while (0); | |||
535 | assert(ret)do { if ((__builtin_expect(!!(!(ret)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("ret"), "../src/journal/mmap-cache.c", 535 , __PRETTY_FUNCTION__); } while (0); | |||
536 | assert(context < MMAP_CACHE_MAX_CONTEXTS)do { if ((__builtin_expect(!!(!(context < 9)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("context < MMAP_CACHE_MAX_CONTEXTS"), "../src/journal/mmap-cache.c", 536, __PRETTY_FUNCTION__); } while (0); | |||
537 | ||||
538 | /* Check whether the current context is the right one already */ | |||
539 | r = try_context(m, f, prot, context, keep_always, offset, size, ret, ret_size); | |||
540 | if (r != 0) { | |||
541 | m->n_hit++; | |||
542 | return r; | |||
543 | } | |||
544 | ||||
545 | /* Search for a matching mmap */ | |||
546 | r = find_mmap(m, f, prot, context, keep_always, offset, size, ret, ret_size); | |||
547 | if (r != 0) { | |||
548 | m->n_hit++; | |||
549 | return r; | |||
550 | } | |||
551 | ||||
552 | m->n_missed++; | |||
553 | ||||
554 | /* Create a new mmap */ | |||
555 | return add_mmap(m, f, prot, context, keep_always, offset, size, st, ret, ret_size); | |||
556 | } | |||
557 | ||||
558 | unsigned mmap_cache_get_hit(MMapCache *m) { | |||
559 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 559 , __PRETTY_FUNCTION__); } while (0); | |||
560 | ||||
561 | return m->n_hit; | |||
562 | } | |||
563 | ||||
564 | unsigned mmap_cache_get_missed(MMapCache *m) { | |||
565 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 565 , __PRETTY_FUNCTION__); } while (0); | |||
566 | ||||
567 | return m->n_missed; | |||
568 | } | |||
569 | ||||
570 | static void mmap_cache_process_sigbus(MMapCache *m) { | |||
571 | bool_Bool found = false0; | |||
572 | MMapFileDescriptor *f; | |||
573 | Iterator i; | |||
574 | int r; | |||
575 | ||||
576 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 576 , __PRETTY_FUNCTION__); } while (0); | |||
577 | ||||
578 | /* Iterate through all triggered pages and mark their files as | |||
579 | * invalidated */ | |||
580 | for (;;) { | |||
581 | bool_Bool ours; | |||
582 | void *addr; | |||
583 | ||||
584 | r = sigbus_pop(&addr); | |||
585 | if (_likely_(r == 0)(__builtin_expect(!!(r == 0),1))) | |||
586 | break; | |||
587 | if (r < 0) { | |||
588 | log_error_errno(r, "SIGBUS handling failed: %m")({ int _level = ((3)), _e = ((r)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/mmap-cache.c", 588, __func__, "SIGBUS handling failed: %m" ) : -abs(_e); }); | |||
589 | abort(); | |||
590 | } | |||
591 | ||||
592 | ours = false0; | |||
593 | HASHMAP_FOREACH(f, m->fds, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((m->fds), &( i), (void**)&(f), ((void*)0)); ) { | |||
594 | Window *w; | |||
595 | ||||
596 | LIST_FOREACH(by_fd, w, f->windows)for ((w) = (f->windows); (w); (w) = (w)->by_fd_next) { | |||
597 | if ((uint8_t*) addr >= (uint8_t*) w->ptr && | |||
598 | (uint8_t*) addr < (uint8_t*) w->ptr + w->size) { | |||
599 | found = ours = f->sigbus = true1; | |||
600 | break; | |||
601 | } | |||
602 | } | |||
603 | ||||
604 | if (ours) | |||
605 | break; | |||
606 | } | |||
607 | ||||
608 | /* Didn't find a matching window, give up */ | |||
609 | if (!ours) { | |||
610 | log_error("Unknown SIGBUS page, aborting.")({ int _level = (((3))), _e = ((0)), _realm = (LOG_REALM_SYSTEMD ); (log_get_max_level_realm(_realm) >= ((_level) & 0x07 )) ? log_internal_realm(((_realm) << 10 | (_level)), _e , "../src/journal/mmap-cache.c", 610, __func__, "Unknown SIGBUS page, aborting." ) : -abs(_e); }); | |||
611 | abort(); | |||
612 | } | |||
613 | } | |||
614 | ||||
615 | /* The list of triggered pages is now empty. Now, let's remap | |||
616 | * all windows of the triggered file to anonymous maps, so | |||
617 | * that no page of the file in question is triggered again, so | |||
618 | * that we can be sure not to hit the queue size limit. */ | |||
619 | if (_likely_(!found)(__builtin_expect(!!(!found),1))) | |||
620 | return; | |||
621 | ||||
622 | HASHMAP_FOREACH(f, m->fds, i)for ((i) = ((Iterator) { .idx = ((2147483647 *2U +1U) - 1), . next_key = ((void*)0) }); hashmap_iterate((m->fds), &( i), (void**)&(f), ((void*)0)); ) { | |||
623 | Window *w; | |||
624 | ||||
625 | if (!f->sigbus) | |||
626 | continue; | |||
627 | ||||
628 | LIST_FOREACH(by_fd, w, f->windows)for ((w) = (f->windows); (w); (w) = (w)->by_fd_next) | |||
629 | window_invalidate(w); | |||
630 | } | |||
631 | } | |||
632 | ||||
633 | bool_Bool mmap_cache_got_sigbus(MMapCache *m, MMapFileDescriptor *f) { | |||
634 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 634 , __PRETTY_FUNCTION__); } while (0); | |||
635 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 635 , __PRETTY_FUNCTION__); } while (0); | |||
636 | ||||
637 | mmap_cache_process_sigbus(m); | |||
638 | ||||
639 | return f->sigbus; | |||
640 | } | |||
641 | ||||
642 | MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd) { | |||
643 | MMapFileDescriptor *f; | |||
644 | int r; | |||
645 | ||||
646 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 646 , __PRETTY_FUNCTION__); } while (0); | |||
647 | assert(fd >= 0)do { if ((__builtin_expect(!!(!(fd >= 0)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("fd >= 0"), "../src/journal/mmap-cache.c" , 647, __PRETTY_FUNCTION__); } while (0); | |||
648 | ||||
649 | f = hashmap_get(m->fds, FD_TO_PTR(fd)((void *) ((intptr_t) ((fd)+1)))); | |||
650 | if (f) | |||
651 | return f; | |||
652 | ||||
653 | r = hashmap_ensure_allocated(&m->fds, NULL)internal_hashmap_ensure_allocated(&m->fds, ((void*)0) ); | |||
654 | if (r < 0) | |||
655 | return NULL((void*)0); | |||
656 | ||||
657 | f = new0(MMapFileDescriptor, 1)((MMapFileDescriptor*) calloc((1), sizeof(MMapFileDescriptor) )); | |||
658 | if (!f) | |||
659 | return NULL((void*)0); | |||
660 | ||||
661 | f->cache = m; | |||
662 | f->fd = fd; | |||
663 | ||||
664 | r = hashmap_put(m->fds, FD_TO_PTR(fd)((void *) ((intptr_t) ((fd)+1))), f); | |||
665 | if (r < 0) | |||
666 | return mfree(f); | |||
667 | ||||
668 | return f; | |||
669 | } | |||
670 | ||||
671 | void mmap_cache_free_fd(MMapCache *m, MMapFileDescriptor *f) { | |||
672 | assert(m)do { if ((__builtin_expect(!!(!(m)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("m"), "../src/journal/mmap-cache.c", 672 , __PRETTY_FUNCTION__); } while (0); | |||
| ||||
673 | assert(f)do { if ((__builtin_expect(!!(!(f)),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("f"), "../src/journal/mmap-cache.c", 673 , __PRETTY_FUNCTION__); } while (0); | |||
674 | ||||
675 | /* Make sure that any queued SIGBUS are first dispatched, so | |||
676 | * that we don't end up with a SIGBUS entry we cannot relate | |||
677 | * to any existing memory map */ | |||
678 | ||||
679 | mmap_cache_process_sigbus(m); | |||
680 | ||||
681 | while (f->windows) | |||
682 | window_free(f->windows); | |||
| ||||
683 | ||||
684 | if (f->cache) | |||
685 | assert_se(hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd)))do { if ((__builtin_expect(!!(!(hashmap_remove(f->cache-> fds, ((void *) ((intptr_t) ((f->fd)+1)))))),0))) log_assert_failed_realm (LOG_REALM_SYSTEMD, ("hashmap_remove(f->cache->fds, FD_TO_PTR(f->fd))" ), "../src/journal/mmap-cache.c", 685, __PRETTY_FUNCTION__); } while (0); | |||
686 | ||||
687 | free(f); | |||
688 | } |