LCOV - code coverage report
Current view: top level - home/snorch/criu - shmem.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 130 150 86.7 %
Date: 2014-04-22 Functions: 10 10 100.0 %
Branches: 64 102 62.7 %

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

Generated by: LCOV version 1.9