LCOV - code coverage report
Current view: top level - journal - mmap-cache.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 246 307 80.1 %
Date: 2019-08-23 13:36:53 Functions: 24 26 92.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 187 320 58.4 %

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

Generated by: LCOV version 1.14