LCOV - code coverage report
Current view: top level - home/snorch/criu - page-read.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 91 116 78.4 %
Date: 2014-04-22 Functions: 10 12 83.3 %
Branches: 51 76 67.1 %

           Branch data     Line data    Source code
       1                 :            : #include <fcntl.h>
       2                 :            : #include <stdio.h>
       3                 :            : #include <unistd.h>
       4                 :            : 
       5                 :            : #include "image.h"
       6                 :            : #include "cr_options.h"
       7                 :            : #include "servicefd.h"
       8                 :            : #include "page-read.h"
       9                 :            : 
      10                 :            : #include "protobuf.h"
      11                 :            : #include "protobuf/pagemap.pb-c.h"
      12                 :            : 
      13                 :            : #ifndef SEEK_DATA
      14                 :            : #define SEEK_DATA       3
      15                 :            : #define SEEK_HOLE       4
      16                 :            : #endif
      17                 :            : 
      18                 :          0 : static int get_page_vaddr(struct page_read *pr, struct iovec *iov)
      19                 :            : {
      20                 :            :         int ret;
      21                 :            :         u64 img_va;
      22                 :            : 
      23                 :          0 :         ret = read_img_eof(pr->fd_pg, &img_va);
      24         [ #  # ]:          0 :         if (ret <= 0)
      25                 :            :                 return ret;
      26                 :            : 
      27                 :          0 :         iov->iov_base = (void *)decode_pointer(img_va);
      28                 :          0 :         iov->iov_len = PAGE_SIZE;
      29                 :            : 
      30                 :          0 :         return 1;
      31                 :            : }
      32                 :            : 
      33                 :          0 : static int read_page(struct page_read *pr, unsigned long vaddr, void *buf)
      34                 :            : {
      35                 :            :         int ret;
      36                 :            : 
      37                 :          0 :         ret = read(pr->fd_pg, buf, PAGE_SIZE);
      38         [ #  # ]:          0 :         if (ret != PAGE_SIZE) {
      39                 :          0 :                 pr_err("Can't read mapping page %d\n", ret);
      40                 :          0 :                 return -1;
      41                 :            :         }
      42                 :            : 
      43                 :            :         return 1;
      44                 :            : }
      45                 :            : 
      46                 :      53622 : void pagemap2iovec(PagemapEntry *pe, struct iovec *iov)
      47                 :            : {
      48                 :    2677296 :         iov->iov_base = decode_pointer(pe->vaddr);
      49                 :     958724 :         iov->iov_len = pe->nr_pages * PAGE_SIZE;
      50                 :      53622 : }
      51                 :            : 
      52                 :     326796 : static int get_pagemap(struct page_read *pr, struct iovec *iov)
      53                 :            : {
      54                 :            :         int ret;
      55                 :            :         PagemapEntry *pe;
      56                 :            : 
      57                 :     326796 :         ret = pb_read_one_eof(pr->fd, &pe, PB_PAGEMAP);
      58         [ +  + ]:     326796 :         if (ret <= 0)
      59                 :            :                 return ret;
      60                 :            : 
      61                 :     326302 :         pagemap2iovec(pe, iov);
      62                 :            : 
      63                 :     326302 :         pr->pe = pe;
      64                 :     326302 :         pr->cvaddr = (unsigned long)iov->iov_base;
      65                 :            : 
      66 [ +  + ][ -  + ]:     326302 :         if (pe->in_parent && !pr->parent) {
      67                 :          0 :                 pr_err("No parent for snapshot pagemap\n");
      68                 :          0 :                 return -1;
      69                 :            :         }
      70                 :            : 
      71                 :            :         return 1;
      72                 :            : }
      73                 :            : 
      74                 :      27530 : static void put_pagemap(struct page_read *pr)
      75                 :            : {
      76                 :     319414 :         pagemap_entry__free_unpacked(pr->pe, NULL);
      77                 :      27530 : }
      78                 :            : 
      79                 :            : static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, void *buf);
      80                 :            : 
      81                 :    1180076 : static void skip_pagemap_pages(struct page_read *pr, unsigned long len)
      82                 :            : {
      83         [ +  + ]:    1180076 :         if (!len)
      84                 :    1180076 :                 return;
      85                 :            : 
      86                 :     284096 :         pr_debug("\tpr%u Skip %lx bytes from page-dump\n", pr->id, len);
      87         [ +  + ]:     284096 :         if (!pr->pe->in_parent)
      88                 :     256989 :                 lseek(pr->fd_pg, len, SEEK_CUR);
      89                 :     284096 :         pr->cvaddr += len;
      90                 :            : }
      91                 :            : 
      92                 :     965612 : int seek_pagemap_page(struct page_read *pr, unsigned long vaddr, bool warn)
      93                 :            : {
      94                 :            :         int ret;
      95                 :            :         struct iovec iov;
      96                 :            : 
      97         [ +  + ]:     965612 :         if (pr->pe)
      98                 :            :                 pagemap2iovec(pr->pe, &iov);
      99                 :            :         else
     100                 :            :                 goto new_pagemap;
     101                 :            : 
     102                 :            :         while (1) {
     103                 :            :                 unsigned long iov_end;
     104                 :            : 
     105         [ +  + ]:    1257496 :                 if (vaddr < pr->cvaddr) {
     106         [ -  + ]:      77420 :                         if (warn)
     107                 :          0 :                                 pr_err("Missing %lu in parent pagemap, current iov: base=%lx,len=%zu\n",
     108                 :            :                                         vaddr, (unsigned long)iov.iov_base, iov.iov_len);
     109                 :            :                         return 0;
     110                 :            :                 }
     111                 :    1180076 :                 iov_end = (unsigned long)iov.iov_base + iov.iov_len;
     112                 :            : 
     113         [ +  + ]:    1180076 :                 if (iov_end <= vaddr) {
     114                 :     291884 :                         skip_pagemap_pages(pr, iov_end - pr->cvaddr);
     115                 :            :                         put_pagemap(pr);
     116                 :            : new_pagemap:
     117                 :     298772 :                         ret = get_pagemap(pr, &iov);
     118         [ +  - ]:     298772 :                         if (ret <= 0)
     119                 :            :                                 return ret;
     120                 :            : 
     121                 :     298772 :                         continue;
     122                 :            :                 }
     123                 :            : 
     124                 :     888192 :                 skip_pagemap_pages(pr, vaddr - pr->cvaddr);
     125                 :     888192 :                 return 1;
     126                 :     298772 :         }
     127                 :            : }
     128                 :            : 
     129                 :    1140216 : static int read_pagemap_page(struct page_read *pr, unsigned long vaddr, void *buf)
     130                 :            : {
     131                 :            :         int ret;
     132                 :            : 
     133         [ +  + ]:    1140216 :         if (pr->pe->in_parent) {
     134                 :     834795 :                 pr_debug("\tpr%u Read page %lx from parent\n", pr->id, vaddr);
     135                 :     834795 :                 ret = seek_pagemap_page(pr->parent, vaddr, true);
     136         [ +  - ]:     834795 :                 if (ret <= 0)
     137                 :            :                         return -1;
     138                 :     834795 :                 ret = read_pagemap_page(pr->parent, vaddr, buf);
     139         [ +  - ]:     834795 :                 if (ret == -1)
     140                 :            :                         return ret;
     141                 :            :         } else {
     142                 :     305421 :                 off_t current_vaddr = lseek(pr->fd_pg, 0, SEEK_CUR);
     143                 :     305421 :                 pr_debug("\tpr%u Read page %lx from self %lx/%"PRIx64"\n", pr->id,
     144                 :            :                                 vaddr, pr->cvaddr, current_vaddr);
     145                 :     610842 :                 ret = read(pr->fd_pg, buf, PAGE_SIZE);
     146         [ -  + ]:     305421 :                 if (ret != PAGE_SIZE) {
     147                 :          0 :                         pr_perror("Can't read mapping page %d", ret);
     148                 :          0 :                         return -1;
     149                 :            :                 }
     150                 :            : 
     151         [ +  - ]:     305421 :                 if (opts.auto_dedup) {
     152                 :     305421 :                         ret = punch_hole(pr, current_vaddr, (unsigned int)PAGE_SIZE, false);
     153         [ +  - ]:     305421 :                         if (ret == -1) {
     154                 :            :                                 return -1;
     155                 :            :                         }
     156                 :            :                 }
     157                 :            :         }
     158                 :            : 
     159                 :    1140216 :         pr->cvaddr += PAGE_SIZE;
     160                 :            : 
     161                 :    1140216 :         return 1;
     162                 :            : }
     163                 :            : 
     164                 :       7391 : static void close_page_read(struct page_read *pr)
     165                 :            : {
     166                 :            :         int ret;
     167                 :            : 
     168         [ +  + ]:       7391 :         if (pr->bunch.iov_len > 0) {
     169                 :       6451 :                 ret = punch_hole(pr, 0, 0, true);
     170         [ +  - ]:       6451 :                 if (ret == -1)
     171                 :       7391 :                         return;
     172                 :            : 
     173                 :       6451 :                 pr->bunch.iov_len = 0;
     174                 :            :         }
     175                 :            : 
     176         [ +  + ]:       7391 :         if (pr->parent) {
     177                 :       4155 :                 close_page_read(pr->parent);
     178         [ +  - ]:       4155 :                 xfree(pr->parent);
     179                 :            :         }
     180                 :            : 
     181                 :       7391 :         close(pr->fd_pg);
     182                 :       7391 :         close(pr->fd);
     183                 :            : }
     184                 :            : 
     185                 :       7371 : static int try_open_parent(int dfd, int pid, struct page_read *pr, int flags)
     186                 :            : {
     187                 :            :         int pfd;
     188                 :            :         struct page_read *parent = NULL;
     189                 :            : 
     190                 :            :         pfd = openat(dfd, CR_PARENT_LINK, O_RDONLY);
     191 [ +  + ][ -  + ]:       7371 :         if (pfd < 0 && errno == ENOENT)
     192                 :            :                 goto out;
     193                 :            : 
     194         [ -  + ]:       4158 :         parent = xmalloc(sizeof(*parent));
     195         [ +  - ]:       4158 :         if (!parent)
     196                 :            :                 goto err_cl;
     197                 :            : 
     198         [ +  + ]:       4158 :         if (open_page_read_at(pfd, pid, parent, flags, false)) {
     199         [ +  - ]:          3 :                 if (errno != ENOENT)
     200                 :            :                         goto err_free;
     201         [ +  - ]:          3 :                 xfree(parent);
     202                 :            :                 parent = NULL;
     203                 :            :         }
     204                 :            : 
     205                 :       4158 :         close(pfd);
     206                 :            : out:
     207                 :       7371 :         pr->parent = parent;
     208                 :            :         return 0;
     209                 :            : 
     210                 :            : err_free:
     211         [ #  # ]:          0 :         xfree(parent);
     212                 :            : err_cl:
     213                 :          0 :         close(pfd);
     214                 :            :         return -1;
     215                 :            : }
     216                 :            : 
     217                 :       7401 : int open_page_read_at(int dfd, int pid, struct page_read *pr, int flags, bool shmem)
     218                 :            : {
     219                 :       7401 :         pr->pe = NULL;
     220                 :       7401 :         pr->parent = NULL;
     221                 :       7401 :         pr->bunch.iov_len = 0;
     222                 :       7401 :         pr->bunch.iov_base = NULL;
     223                 :            : 
     224         [ +  + ]:       7401 :         pr->fd = open_image_at(dfd, shmem ? CR_FD_SHMEM_PAGEMAP : CR_FD_PAGEMAP, O_RSTR, (long)pid);
     225         [ +  + ]:       7401 :         if (pr->fd < 0) {
     226         [ +  - ]:         10 :                 pr->fd_pg = open_image_at(dfd, shmem ? CR_FD_SHM_PAGES_OLD : CR_FD_PAGES_OLD, flags, pid);
     227         [ -  + ]:         10 :                 if (pr->fd_pg < 0)
     228                 :            :                         return -1;
     229                 :            : 
     230                 :          0 :                 pr->get_pagemap = get_page_vaddr;
     231                 :          0 :                 pr->put_pagemap = NULL;
     232                 :          0 :                 pr->read_page = read_page;
     233                 :            :         } else {
     234                 :            :                 static unsigned ids = 1;
     235                 :            : 
     236 [ +  + ][ -  + ]:       7391 :                 if (!shmem && try_open_parent(dfd, pid, pr, flags)) {
     237                 :          0 :                         close(pr->fd);
     238                 :          0 :                         return -1;
     239                 :            :                 }
     240                 :            : 
     241                 :       7391 :                 pr->fd_pg = open_pages_image_at(dfd, flags, pr->fd);
     242         [ -  + ]:       7391 :                 if (pr->fd_pg < 0) {
     243                 :          0 :                         close_page_read(pr);
     244                 :          0 :                         return -1;
     245                 :            :                 }
     246                 :            : 
     247                 :       7391 :                 pr->get_pagemap = get_pagemap;
     248                 :       7391 :                 pr->put_pagemap = put_pagemap;
     249                 :       7391 :                 pr->read_page = read_pagemap_page;
     250                 :       7391 :                 pr->id = ids++;
     251                 :            : 
     252         [ +  + ]:       7391 :                 pr_debug("Opened page read %u (parent %u)\n",
     253                 :            :                                 pr->id, pr->parent ? pr->parent->id : 0);
     254                 :            :         }
     255                 :            : 
     256                 :       7391 :         pr->close = close_page_read;
     257                 :            : 
     258                 :       7391 :         return 0;
     259                 :            : }
     260                 :            : 
     261                 :        494 : int open_page_read(int pid, struct page_read *pr, int flags, bool shmem)
     262                 :            : {
     263                 :        494 :         return open_page_read_at(get_service_fd(IMG_FD_OFF), pid, pr, flags, shmem);
     264                 :            : }

Generated by: LCOV version 1.9