LCOV - code coverage report
Current view: top level - crtools - shmem.c (source / functions) Hit Total Coverage
Test: crtools.info Lines: 132 147 89.8 %
Date: 2012-12-28 Functions: 9 9 100.0 %
Branches: 63 94 67.0 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <sys/mman.h>
       3                 :            : #include <stdlib.h>
       4                 :            : 
       5                 :            : #include "shmem.h"
       6                 :            : #include "image.h"
       7                 :            : #include "crtools.h"
       8                 :            : #include "restorer.h"
       9                 :            : 
      10                 :            : #include "protobuf.h"
      11                 :            : 
      12                 :            : struct shmems *rst_shmems;
      13                 :            : 
      14                 :        355 : void show_saved_shmems(void)
      15                 :            : {
      16                 :            :         int i;
      17                 :            : 
      18                 :        355 :         pr_info("\tSaved shmems:\n");
      19                 :            : 
      20         [ +  + ]:        417 :         for (i = 0; i < rst_shmems->nr_shmems; i++)
      21                 :         62 :                 pr_info("\t\tstart: 0x%016lx shmid: 0x%lx pid: %d\n",
      22                 :            :                         rst_shmems->entries[i].start,
      23                 :            :                         rst_shmems->entries[i].shmid,
      24                 :            :                         rst_shmems->entries[i].pid);
      25                 :        355 : }
      26                 :            : 
      27                 :        274 : static int collect_shmem(int pid, VmaEntry *vi)
      28                 :            : {
      29                 :        274 :         int nr_shmems = rst_shmems->nr_shmems;
      30                 :        274 :         unsigned long size = vi->pgoff + vi->end - vi->start;
      31                 :            :         struct shmem_info *si;
      32                 :            : 
      33                 :        548 :         si = find_shmem(rst_shmems, vi->shmid);
      34         [ +  + ]:        274 :         if (si) {
      35                 :            : 
      36         [ +  + ]:        212 :                 if (si->size < size)
      37                 :         10 :                         si->size = size;
      38                 :            : 
      39                 :            :                 /*
      40                 :            :                  * Only the shared mapping with a lowest
      41                 :            :                  * pid will be created in real, other processes
      42                 :            :                  * will wait until the kernel propagate this mapping
      43                 :            :                  * into /proc
      44                 :            :                  */
      45         [ +  + ]:        212 :                 if (si->pid <= pid)
      46                 :            :                         return 0;
      47                 :            : 
      48                 :         14 :                 si->pid       = pid;
      49                 :         14 :                 si->start = vi->start;
      50                 :         14 :                 si->end       = vi->end;
      51                 :            : 
      52                 :         14 :                 return 0;
      53                 :            :         }
      54                 :            : 
      55         [ -  + ]:         62 :         if ((nr_shmems + 1) * sizeof(struct shmem_info) +
      56                 :            :                                         sizeof (struct shmems) >= SHMEMS_SIZE) {
      57                 :          0 :                 pr_err("OOM storing shmems\n");
      58                 :          0 :                 return -1;
      59                 :            :         }
      60                 :            : 
      61                 :         62 :         pr_info("Add new shmem 0x%lx (0x0160x%lx-0x0160x%lx)",
      62                 :            :                                 vi->shmid, vi->start, vi->end);
      63                 :            : 
      64                 :         62 :         si = &rst_shmems->entries[nr_shmems];
      65                 :         62 :         rst_shmems->nr_shmems++;
      66                 :            : 
      67                 :         62 :         si->start = vi->start;
      68                 :         62 :         si->end        = vi->end;
      69                 :         62 :         si->shmid = vi->shmid;
      70                 :         62 :         si->pid        = pid;
      71                 :         62 :         si->size  = size;
      72                 :         62 :         si->fd    = -1;
      73                 :            : 
      74                 :         62 :         futex_init(&si->lock);
      75                 :            : 
      76                 :        274 :         return 0;
      77                 :            : }
      78                 :            : 
      79                 :       1459 : int prepare_shmem_pid(int pid)
      80                 :            : {
      81                 :       1459 :         int fd, ret = -1;
      82                 :            :         VmaEntry *vi;
      83                 :            : 
      84                 :       1459 :         fd = open_image_ro(CR_FD_VMAS, pid);
      85         [ +  + ]:       1459 :         if (fd < 0) {
      86         [ -  + ]:      24567 :                 if (errno == ENOENT)
      87                 :            :                         return 0;
      88                 :            :                 else
      89                 :            :                         return -1;
      90                 :            :         }
      91                 :            : 
      92                 :            :         while (1) {
      93                 :      25960 :                 ret = pb_read_one_eof(fd, &vi, PB_VMAS);
      94         [ +  + ]:      25960 :                 if (ret <= 0)
      95                 :            :                         break;
      96                 :            : 
      97                 :      24534 :                 pr_info("vma 0x%lx 0x%lx\n", vi->start, vi->end);
      98                 :            : 
      99         [ +  + ]:      24534 :                 if (!vma_entry_is(vi, VMA_ANON_SHARED) ||
     100                 :            :                     vma_entry_is(vi, VMA_AREA_SYSVIPC)) {
     101                 :      24260 :                         vma_entry__free_unpacked(vi, NULL);
     102                 :      24260 :                         continue;
     103                 :            :                 }
     104                 :            : 
     105                 :        274 :                 ret = collect_shmem(pid, vi);
     106                 :        274 :                 vma_entry__free_unpacked(vi, NULL);
     107                 :            : 
     108         [ +  - ]:        274 :                 if (ret)
     109                 :            :                         break;
     110                 :            :         }
     111                 :            : 
     112                 :       1459 :         close(fd);
     113                 :            :         return ret;
     114                 :            : }
     115                 :            : 
     116                 :         21 : static int shmem_wait_and_open(int pid, struct shmem_info *si)
     117                 :            : {
     118                 :            :         char path[128];
     119                 :            :         int ret;
     120                 :            : 
     121                 :         21 :         snprintf(path, sizeof(path), "/proc/%d/map_files/%lx-%lx",
     122                 :            :                 si->pid, si->start, si->end);
     123                 :            : 
     124                 :         21 :         pr_info("Waiting for [%s] to appear\n", path);
     125                 :         21 :         futex_wait_until(&si->lock, 1);
     126                 :            : 
     127                 :         21 :         pr_info("Opening shmem [%s] \n", path);
     128         [ -  + ]:         21 :         ret = open_proc_rw(si->pid, "map_files/%lx-%lx", si->start, si->end);
     129         [ -  + ]:         21 :         if (ret < 0)
     130                 :          0 :                 pr_perror("     %d: Can't stat shmem at %s",
     131                 :            :                                 si->pid, path);
     132                 :         21 :         return ret;
     133                 :            : }
     134                 :            : 
     135                 :         19 : static int restore_shmem_content(void *addr, struct shmem_info *si)
     136                 :            : {
     137                 :            :         u64 offset;
     138                 :         19 :         int fd, ret = 0;
     139                 :            : 
     140                 :         19 :         fd = open_image_ro(CR_FD_SHMEM_PAGES, si->shmid);
     141         [ -  + ]:         19 :         if (fd < 0) {
     142                 :         19 :                 munmap(addr,  si->size);
     143                 :            :                 return -1;
     144                 :            :         }
     145                 :            : 
     146                 :            :         while (1) {
     147                 :         40 :                 ret = read_img_buf_eof(fd, &offset, sizeof(offset));
     148         [ +  + ]:         40 :                 if (ret <= 0)
     149                 :            :                         break;
     150                 :            : 
     151         [ +  - ]:         21 :                 if (offset + PAGE_SIZE > si->size)
     152                 :            :                         break;
     153                 :            : 
     154                 :         21 :                 ret = read_img_buf(fd, addr + offset, PAGE_SIZE);
     155         [ +  - ]:         21 :                 if (ret < 0)
     156                 :            :                         break;
     157                 :            :         }
     158                 :            : 
     159                 :         19 :         close(fd);
     160                 :            :         return ret;
     161                 :            : }
     162                 :            : 
     163                 :         44 : int get_shmem_fd(int pid, VmaEntry *vi)
     164                 :            : {
     165                 :            :         struct shmem_info *si;
     166                 :            :         void *addr;
     167                 :            :         int f;
     168                 :            : 
     169                 :         88 :         si = find_shmem(rst_shmems, vi->shmid);
     170         [ +  - ]:         44 :         pr_info("Search for 0x%016lx shmem 0x%lx %p/%d\n", vi->start, vi->shmid, si, si ? si->pid : -1);
     171         [ -  + ]:         44 :         if (!si) {
     172                 :          0 :                 pr_err("Can't find my shmem 0x%016lx\n", vi->start);
     173                 :          0 :                 return -1;
     174                 :            :         }
     175                 :            : 
     176         [ +  + ]:         44 :         if (si->pid != pid)
     177                 :         21 :                 return shmem_wait_and_open(pid, si);
     178                 :            : 
     179         [ +  + ]:         23 :         if (si->fd != -1)
     180                 :          4 :                 return dup(si->fd);
     181                 :            : 
     182                 :            :         /*
     183                 :            :          * The following hack solves problems:
     184                 :            :          * vi->pgoff may be not zero in a target process.
     185                 :            :          * This mapping may be mapped more then once.
     186                 :            :          * The restorer doesn't have snprintf.
     187                 :            :          * Here is a good place to restore content
     188                 :            :          */
     189                 :         19 :         addr = mmap(NULL, si->size,
     190                 :            :                         PROT_WRITE | PROT_READ,
     191                 :            :                         MAP_SHARED | MAP_ANONYMOUS, -1, 0);
     192         [ -  + ]:         19 :         if (addr == MAP_FAILED) {
     193                 :          0 :                 pr_err("Can't mmap shmid=0x%lx size=%ld\n",
     194                 :            :                                 vi->shmid, si->size);
     195                 :          0 :                 return -1;
     196                 :            :         }
     197                 :            : 
     198         [ -  + ]:         19 :         if (restore_shmem_content(addr, si) < 0) {
     199                 :          0 :                 pr_err("Can't restore shmem content\n");
     200                 :          0 :                 return -1;
     201                 :            :         }
     202                 :            : 
     203         [ -  + ]:         19 :         f = open_proc_rw(getpid(), "map_files/%lx-%lx",
     204                 :            :                         (unsigned long) addr,
     205                 :            :                         (unsigned long) addr + si->size);
     206                 :         19 :         munmap(addr, si->size);
     207         [ +  - ]:         19 :         if (f < 0)
     208                 :            :                 return -1;
     209                 :            : 
     210                 :         19 :         si->fd = f;
     211                 :         44 :         return f;
     212                 :            : }
     213                 :            : 
     214                 :        355 : int prepare_shmem_restore(void)
     215                 :            : {
     216                 :        355 :         rst_shmems = mmap(NULL, SHMEMS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, 0, 0);
     217         [ -  + ]:        355 :         if (rst_shmems == MAP_FAILED) {
     218                 :          0 :                 pr_perror("Can't map shmem");
     219                 :          0 :                 return -1;
     220                 :            :         }
     221                 :            : 
     222                 :        355 :         rst_shmems->nr_shmems = 0;
     223                 :        355 :         return 0;
     224                 :            : }
     225                 :            : 
     226                 :            : struct shmem_info_dump {
     227                 :            :         unsigned long   size;
     228                 :            :         unsigned long   shmid;
     229                 :            :         unsigned long   start;
     230                 :            :         unsigned long   end;
     231                 :            :         int             pid;
     232                 :            : 
     233                 :            :         struct shmem_info_dump *next;
     234                 :            : };
     235                 :            : 
     236                 :            : #define SHMEM_HASH_SIZE 32
     237                 :            : static struct shmem_info_dump *shmems_hash[SHMEM_HASH_SIZE];
     238                 :            : 
     239                 :            : static struct shmem_info_dump *shmem_find(struct shmem_info_dump **chain,
     240                 :            :                 unsigned long shmid)
     241                 :            : {
     242                 :            :         struct shmem_info_dump *sh;
     243                 :            : 
     244         [ +  + ]:         44 :         for (sh = *chain; sh; sh = sh->next)
     245         [ -  + ]:         25 :                 if (sh->shmid == shmid)
     246                 :            :                         return sh;
     247                 :            : 
     248                 :            :         return NULL;
     249                 :            : }
     250                 :            : 
     251                 :         44 : int add_shmem_area(pid_t pid, VmaEntry *vma)
     252                 :            : {
     253                 :            :         struct shmem_info_dump *si, **chain;
     254                 :         44 :         unsigned long size = vma->pgoff + (vma->end - vma->start);
     255                 :            : 
     256                 :         44 :         chain = &shmems_hash[vma->shmid % SHMEM_HASH_SIZE];
     257                 :         88 :         si = shmem_find(chain, vma->shmid);
     258         [ +  + ]:         44 :         if (si) {
     259         [ +  + ]:         25 :                 if (si->size < size)
     260                 :          4 :                         si->size = size;
     261                 :            :                 return 0;
     262                 :            :         }
     263                 :            : 
     264         [ -  + ]:         19 :         si = xmalloc(sizeof(*si));
     265         [ +  - ]:         19 :         if (!si)
     266                 :            :                 return -1;
     267                 :            : 
     268                 :         19 :         si->next = *chain;
     269                 :         19 :         *chain = si;
     270                 :            : 
     271                 :         19 :         si->size = size;
     272                 :         19 :         si->pid = pid;
     273                 :         19 :         si->start = vma->start;
     274                 :         19 :         si->end = vma->end;
     275                 :         19 :         si->shmid = vma->shmid;
     276                 :            : 
     277                 :         44 :         return 0;
     278                 :            : }
     279                 :            : 
     280                 :            : #define for_each_shmem_dump(_i, _si)                            \
     281                 :            :         for (i = 0; i < SHMEM_HASH_SIZE; i++)                        \
     282                 :            :                 for (si = shmems_hash[i]; si; si = si->next)
     283                 :            : 
     284                 :        166 : int cr_dump_shmem(void)
     285                 :            : {
     286                 :            :         int i, err, fd;
     287                 :        166 :         unsigned char *map = NULL;
     288                 :        166 :         void *addr = NULL;
     289                 :            :         struct shmem_info_dump *si;
     290                 :            :         unsigned long pfn, nrpages;
     291                 :            : 
     292 [ +  + ][ +  + ]:       5497 :         for_each_shmem_dump (i, si) {
     293                 :         19 :                 pr_info("Dumping shared memory 0x%lx\n", si->shmid);
     294                 :            : 
     295                 :         19 :                 nrpages = (si->size + PAGE_SIZE - 1) / PAGE_SIZE;
     296         [ -  + ]:         19 :                 map = xmalloc(nrpages * sizeof(*map));
     297         [ +  - ]:         19 :                 if (!map)
     298                 :            :                         goto err;
     299                 :            : 
     300         [ -  + ]:         19 :                 fd = open_proc(si->pid, "map_files/%lx-%lx", si->start, si->end);
     301         [ +  - ]:         19 :                 if (fd < 0)
     302                 :            :                         goto err;
     303                 :            : 
     304                 :         19 :                 addr = mmap(NULL, si->size, PROT_READ, MAP_SHARED, fd, 0);
     305                 :         19 :                 close(fd);
     306         [ -  + ]:         19 :                 if (addr == MAP_FAILED) {
     307                 :          0 :                         pr_err("Can't map shmem 0x%lx (0x%lx-0x%lx)\n",
     308                 :            :                                         si->shmid, si->start, si->end);
     309                 :          0 :                         goto err;
     310                 :            :                 }
     311                 :            : 
     312                 :            :                 /*
     313                 :            :                  * We can't use pagemap here, because this vma is
     314                 :            :                  * not mapped to us at all, but mincore reports the
     315                 :            :                  * pagecache status of a file, which is correct in
     316                 :            :                  * this case.
     317                 :            :                  */
     318                 :            : 
     319                 :         19 :                 err = mincore(addr, si->size, map);
     320         [ +  - ]:         19 :                 if (err)
     321                 :            :                         goto err_unmap;
     322                 :            : 
     323                 :         19 :                 fd = open_image(CR_FD_SHMEM_PAGES, O_DUMP, si->shmid);
     324         [ +  - ]:         19 :                 if (fd < 0)
     325                 :            :                         goto err_unmap;
     326                 :            : 
     327         [ +  + ]:     524332 :                 for (pfn = 0; pfn < nrpages; pfn++) {
     328                 :     524313 :                         u64 offset = pfn * PAGE_SIZE;
     329                 :            : 
     330         [ +  + ]:     524313 :                         if (!(map[pfn] & PAGE_RSS))
     331                 :     524292 :                                 continue;
     332                 :            : 
     333         [ +  - ]:         21 :                         if (write_img_buf(fd, &offset, sizeof(offset)))
     334                 :            :                                 break;
     335         [ +  - ]:         21 :                         if (write_img_buf(fd, addr + offset, PAGE_SIZE))
     336                 :            :                                 break;
     337                 :            :                 }
     338                 :            : 
     339         [ +  - ]:         19 :                 if (pfn != nrpages)
     340                 :            :                         goto err_close;
     341                 :            : 
     342                 :         19 :                 close(fd);
     343                 :         19 :                 munmap(addr,  si->size);
     344         [ +  - ]:         19 :                 xfree(map);
     345                 :            :         }
     346                 :            : 
     347                 :            :         return 0;
     348                 :            : 
     349                 :            : err_close:
     350                 :          0 :         close(fd);
     351                 :            : err_unmap:
     352                 :          0 :         munmap(addr,  si->size);
     353                 :            : err:
     354         [ #  # ]:        166 :         xfree(map);
     355                 :            :         return -1;
     356                 :         63 : }

Generated by: LCOV version 1.9