LCOV - code coverage report
Current view: top level - home/snorch/criu - cr-dedup.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 38 79 48.1 %
Date: 2014-04-22 Functions: 2 4 50.0 %
Branches: 28 64 43.8 %

           Branch data     Line data    Source code
       1                 :            : #include <sys/uio.h>
       2                 :            : #include <fcntl.h>
       3                 :            : #include <linux/falloc.h>
       4                 :            : #include <unistd.h>
       5                 :            : 
       6                 :            : #include "crtools.h"
       7                 :            : #include "page-read.h"
       8                 :            : #include "restorer.h"
       9                 :            : 
      10                 :            : #define MAX_BUNCH_SIZE 256
      11                 :            : 
      12                 :            : static int cr_dedup_one_pagemap(int pid);
      13                 :            : 
      14                 :          0 : int cr_dedup(void)
      15                 :            : {
      16                 :            :         int close_ret, ret = 0;
      17                 :            :         int pid;
      18                 :            :         DIR * dirp;
      19                 :            :         struct dirent *ent;
      20                 :            : 
      21                 :          0 :         dirp = opendir(CR_PARENT_LINK);
      22         [ #  # ]:          0 :         if (dirp == NULL) {
      23                 :          0 :                 pr_perror("Can't enter previous snapshot folder, error=%d", errno);
      24                 :            :                 ret = -1;
      25                 :          0 :                 goto err;
      26                 :            :         }
      27                 :            : 
      28                 :            :         while (1) {
      29                 :          0 :                 errno = 0;
      30                 :          0 :                 ent = readdir(dirp);
      31         [ #  # ]:          0 :                 if (ent == NULL) {
      32         [ #  # ]:          0 :                         if (errno) {
      33                 :          0 :                                 pr_perror("Failed readdir, error=%d", errno);
      34                 :            :                                 ret = -1;
      35                 :          0 :                                 goto err;
      36                 :            :                         }
      37                 :            :                         break;
      38                 :            :                 }
      39                 :            : 
      40                 :          0 :                 ret = sscanf(ent->d_name, "pagemap-%d.img", &pid);
      41         [ #  # ]:          0 :                 if (ret == 1) {
      42                 :          0 :                         pr_info("pid=%d\n", pid);
      43                 :          0 :                         ret = cr_dedup_one_pagemap(pid);
      44         [ #  # ]:          0 :                         if (ret < 0)
      45                 :            :                                 break;
      46                 :            :                 }
      47                 :            :         }
      48                 :            : 
      49                 :            : err:
      50         [ #  # ]:          0 :         if (dirp) {
      51                 :          0 :                 close_ret = closedir(dirp);
      52         [ #  # ]:          0 :                 if (close_ret == -1)
      53                 :            :                         return close_ret;
      54                 :            :         }
      55                 :            : 
      56         [ #  # ]:          0 :         if (ret < 0)
      57                 :            :                 return ret;
      58                 :            : 
      59                 :          0 :         pr_info("Deduplicated\n");
      60                 :          0 :         return 0;
      61                 :            : }
      62                 :            : 
      63                 :          0 : static int cr_dedup_one_pagemap(int pid)
      64                 :            : {
      65                 :            :         int ret;
      66                 :            :         struct page_read pr;
      67                 :            :         struct page_read * prp;
      68                 :            :         struct iovec iov;
      69                 :            : 
      70                 :          0 :         ret = open_page_read(pid, &pr, O_RDWR, false);
      71         [ #  # ]:          0 :         if (ret) {
      72                 :            :                 ret = -1;
      73                 :            :                 goto exit;
      74                 :            :         }
      75                 :            : 
      76                 :          0 :         prp = pr.parent;
      77         [ #  # ]:          0 :         if (!prp)
      78                 :            :                 goto exit;
      79                 :            : 
      80                 :          0 :         ret = pr.get_pagemap(&pr, &iov);
      81         [ #  # ]:          0 :         if (ret <= 0)
      82                 :            :                 goto exit;
      83                 :            : 
      84                 :            :         while (1) {
      85                 :          0 :                 pr_debug("dedup iovec base=%p, len=%zu\n", iov.iov_base, iov.iov_len);
      86         [ #  # ]:          0 :                 if (!pr.pe->in_parent) {
      87                 :          0 :                         ret = dedup_one_iovec(prp, &iov);
      88         [ #  # ]:          0 :                         if (ret)
      89                 :            :                                 goto exit;
      90                 :            :                 }
      91                 :            : 
      92                 :          0 :                 pr.put_pagemap(&pr);
      93                 :          0 :                 ret = pr.get_pagemap(&pr, &iov);
      94         [ #  # ]:          0 :                 if (ret <= 0)
      95                 :            :                         goto exit;
      96                 :            :         }
      97                 :            : exit:
      98                 :          0 :         pr.close(&pr);
      99                 :            : 
     100         [ #  # ]:          0 :         if (ret < 0)
     101                 :          0 :                 return ret;
     102                 :            : 
     103                 :            :         return 0;
     104                 :            : }
     105                 :            : 
     106                 :            : static inline bool can_extend_batch(struct iovec *bunch,
     107                 :            :                 unsigned long off, unsigned long len)
     108                 :            : {
     109                 :     327102 :         return  /* The next region is the continuation of the existing */
     110 [ +  + ][ +  + ]:     327102 :                 ((unsigned long)bunch->iov_base + bunch->iov_len == off) &&
     111                 :            :                 /* The resulting region is non empty and is small enough */
     112         [ +  + ]:     321135 :                 (bunch->iov_len == 0 || bunch->iov_len + len < MAX_BUNCH_SIZE * PAGE_SIZE);
     113                 :            : }
     114                 :            : 
     115                 :     333547 : int punch_hole(struct page_read *pr, unsigned long off, unsigned long len,
     116                 :            :                bool cleanup)
     117                 :            : {
     118                 :            :         int ret;
     119                 :            :         struct iovec * bunch = &pr->bunch;
     120                 :            : 
     121 [ +  + ][ +  + ]:     660649 :         if (!cleanup && can_extend_batch(bunch, off, len)) {
     122                 :     315038 :                 pr_debug("pr%d:Extend bunch len from %zu to %lu\n", pr->id,
     123                 :            :                          bunch->iov_len, bunch->iov_len + len);
     124                 :     315038 :                 bunch->iov_len += len;
     125                 :            :         } else {
     126         [ +  + ]:      18509 :                 if (bunch->iov_len > 0) {
     127                 :      18031 :                         pr_debug("Punch!/%p/%zu/\n", bunch->iov_base, bunch->iov_len);
     128                 :      18031 :                         ret = fallocate(pr->fd_pg, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
     129                 :      36062 :                                         (unsigned long)bunch->iov_base, bunch->iov_len);
     130         [ -  + ]:      18031 :                         if (ret != 0) {
     131                 :          0 :                                 pr_perror("Error punching hole");
     132                 :          0 :                                 return -1;
     133                 :            :                         }
     134                 :            :                 }
     135                 :      18509 :                 bunch->iov_base = (void *)off;
     136                 :      18509 :                 bunch->iov_len = len;
     137                 :      18509 :                 pr_debug("pr%d:New bunch/%p/%zu/\n", pr->id, bunch->iov_base, bunch->iov_len);
     138                 :            :         }
     139                 :            :         return 0;
     140                 :            : }
     141                 :            : 
     142                 :      98799 : int dedup_one_iovec(struct page_read *pr, struct iovec *iov)
     143                 :            : {
     144                 :            :         unsigned long off;
     145                 :            :         unsigned long off_real;
     146                 :            :         unsigned long iov_end;
     147                 :            : 
     148                 :      98799 :         iov_end = (unsigned long)iov->iov_base + iov->iov_len;
     149                 :            :         off = (unsigned long)iov->iov_base;
     150                 :            :         while (1) {
     151                 :            :                 int ret;
     152                 :            :                 struct iovec piov;
     153                 :            :                 unsigned long piov_end;
     154                 :            :                 struct iovec tiov;
     155                 :            :                 struct page_read * prp;
     156                 :            : 
     157                 :      99022 :                 ret = seek_pagemap_page(pr, off, false);
     158         [ +  - ]:      99022 :                 if (ret == -1)
     159                 :      98799 :                         return -1;
     160                 :            : 
     161         [ +  + ]:      99022 :                 if (ret == 0) {
     162 [ +  - ][ +  + ]:      77420 :                         if (off < pr->cvaddr && pr->cvaddr < iov_end)
     163                 :            :                                 off = pr->cvaddr;
     164                 :            :                         else
     165                 :            :                                 return 0;
     166                 :            :                 }
     167                 :            : 
     168         [ +  - ]:      21827 :                 if (!pr->pe)
     169                 :            :                         return -1;
     170                 :      21827 :                 pagemap2iovec(pr->pe, &piov);
     171                 :      21827 :                 piov_end = (unsigned long)piov.iov_base + piov.iov_len;
     172                 :      21827 :                 off_real = lseek(pr->fd_pg, 0, SEEK_CUR);
     173         [ +  + ]:      21827 :                 if (!pr->pe->in_parent) {
     174                 :      21741 :                         ret = punch_hole(pr, off_real, min(piov_end, iov_end) - off, false);
     175         [ +  - ]:      21741 :                         if (ret == -1)
     176                 :            :                                 return ret;
     177                 :            :                 }
     178                 :            : 
     179                 :      21827 :                 prp = pr->parent;
     180         [ +  + ]:      21827 :                 if (prp) {
     181                 :            :                         /* recursively */
     182                 :      11335 :                         pr_debug("Go to next parent level\n");
     183                 :      11335 :                         tiov.iov_base = (void*)off;
     184                 :      11335 :                         tiov.iov_len = min(piov_end, iov_end) - off;
     185                 :      11335 :                         ret = dedup_one_iovec(prp, &tiov);
     186         [ +  - ]:      11335 :                         if (ret != 0)
     187                 :            :                                 return -1;
     188                 :            :                 }
     189                 :            : 
     190         [ +  + ]:      21827 :                 if (piov_end < iov_end) {
     191                 :            :                         off = piov_end;
     192                 :        223 :                         continue;
     193                 :            :                 } else
     194                 :            :                         return 0;
     195                 :            :         }
     196                 :            :         return 0;
     197                 :            : }

Generated by: LCOV version 1.9