LCOV - code coverage report
Current view: top level - home/snorch/criu - page-pipe.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 100 114 87.7 %
Date: 2014-04-22 Functions: 8 9 88.9 %
Branches: 46 74 62.2 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <fcntl.h>
       3                 :            : 
       4                 :            : #undef LOG_PREFIX
       5                 :            : #define LOG_PREFIX "page-pipe: "
       6                 :            : 
       7                 :            : #include "config.h"
       8                 :            : #include "util.h"
       9                 :            : #include "page-pipe.h"
      10                 :            : 
      11                 :       4938 : static int page_pipe_grow(struct page_pipe *pp)
      12                 :            : {
      13                 :            :         struct page_pipe_buf *ppb;
      14                 :            : 
      15                 :       4938 :         pr_debug("Will grow page pipe (iov off is %u)\n", pp->free_iov);
      16                 :            : 
      17         [ -  + ]:       4938 :         if (!list_empty(&pp->free_bufs)) {
      18                 :          0 :                 ppb = list_first_entry(&pp->free_bufs, struct page_pipe_buf, l);
      19                 :          0 :                 list_move_tail(&ppb->l, &pp->bufs);
      20                 :            :                 goto out;
      21                 :            :         }
      22                 :            : 
      23 [ +  + ][ +  - ]:       4938 :         if (pp->chunk_mode && pp->nr_pipes == NR_PIPES_PER_CHUNK)
      24                 :            :                 return -EAGAIN;
      25                 :            : 
      26         [ -  + ]:       4938 :         ppb = xmalloc(sizeof(*ppb));
      27         [ +  - ]:       4938 :         if (!ppb)
      28                 :            :                 return -1;
      29                 :            : 
      30         [ -  + ]:       4938 :         if (pipe(ppb->p)) {
      31         [ #  # ]:          0 :                 xfree(ppb);
      32                 :          0 :                 pr_perror("Can't make pipe for page-pipe");
      33                 :          0 :                 return -1;
      34                 :            :         }
      35                 :            : 
      36                 :       4938 :         ppb->pipe_size = fcntl(ppb->p[0], F_GETPIPE_SZ, 0) / PAGE_SIZE;
      37                 :            : 
      38                 :       4938 :         list_add_tail(&ppb->l, &pp->bufs);
      39                 :            : out:
      40                 :       4938 :         ppb->pages_in = 0;
      41                 :       4938 :         ppb->nr_segs = 0;
      42                 :       4938 :         ppb->iov = &pp->iovs[pp->free_iov];
      43                 :            : 
      44                 :       4938 :         pp->nr_pipes++;
      45                 :            : 
      46                 :       4938 :         return 0;
      47                 :            : }
      48                 :            : 
      49                 :       3706 : struct page_pipe *create_page_pipe(unsigned int nr_segs,
      50                 :            :                                    struct iovec *iovs, bool chunk_mode)
      51                 :            : {
      52                 :            :         struct page_pipe *pp;
      53                 :            : 
      54                 :       3706 :         pr_debug("Create page pipe for %u segs\n", nr_segs);
      55                 :            : 
      56         [ -  + ]:       3706 :         pp = xmalloc(sizeof(*pp));
      57         [ +  - ]:       3706 :         if (pp) {
      58                 :       3706 :                 pp->nr_pipes = 0;
      59                 :       3706 :                 INIT_LIST_HEAD(&pp->bufs);
      60                 :       3706 :                 INIT_LIST_HEAD(&pp->free_bufs);
      61                 :       3706 :                 pp->nr_iovs = nr_segs;
      62                 :       3706 :                 pp->iovs = iovs;
      63                 :       3706 :                 pp->free_iov = 0;
      64                 :            : 
      65                 :       3706 :                 pp->nr_holes = 0;
      66                 :       3706 :                 pp->free_hole = 0;
      67                 :       3706 :                 pp->holes = NULL;
      68                 :            : 
      69                 :       3706 :                 pp->chunk_mode = chunk_mode;
      70                 :            : 
      71         [ +  - ]:       3706 :                 if (page_pipe_grow(pp))
      72                 :            :                         return NULL;
      73                 :            :         }
      74                 :            : 
      75                 :       3706 :         return pp;
      76                 :            : }
      77                 :            : 
      78                 :       3706 : void destroy_page_pipe(struct page_pipe *pp)
      79                 :            : {
      80                 :            :         struct page_pipe_buf *ppb, *n;
      81                 :            : 
      82                 :       3706 :         pr_debug("Killing page pipe\n");
      83                 :            : 
      84                 :       3706 :         list_splice(&pp->free_bufs, &pp->bufs);
      85         [ +  + ]:       8644 :         list_for_each_entry_safe(ppb, n, &pp->bufs, l) {
      86                 :       4938 :                 close(ppb->p[0]);
      87                 :       4938 :                 close(ppb->p[1]);
      88         [ +  - ]:       4938 :                 xfree(ppb);
      89                 :            :         }
      90                 :            : 
      91         [ +  - ]:       3706 :         xfree(pp);
      92                 :       3706 : }
      93                 :            : 
      94                 :          0 : void page_pipe_reinit(struct page_pipe *pp)
      95                 :            : {
      96                 :            :         struct page_pipe_buf *ppb, *n;
      97                 :            : 
      98         [ #  # ]:          0 :         BUG_ON(!pp->chunk_mode);
      99                 :            : 
     100                 :          0 :         pr_debug("Clean up page pipe\n");
     101                 :            : 
     102         [ #  # ]:          0 :         list_for_each_entry_safe(ppb, n, &pp->bufs, l)
     103                 :          0 :                 list_move(&ppb->l, &pp->free_bufs);
     104                 :            : 
     105                 :          0 :         pp->free_hole = 0;
     106                 :            : 
     107         [ #  # ]:          0 :         if (page_pipe_grow(pp))
     108                 :          0 :                 BUG(); /* It can't fail, because ppb is in free_bufs */
     109                 :          0 : }
     110                 :            : 
     111                 :    1383968 : static inline int try_add_page_to(struct page_pipe *pp, struct page_pipe_buf *ppb,
     112                 :            :                 unsigned long addr)
     113                 :            : {
     114                 :            :         struct iovec *iov;
     115                 :            : 
     116         [ +  + ]:     691984 :         if (ppb->pages_in == ppb->pipe_size) {
     117                 :       8885 :                 unsigned long new_size = ppb->pipe_size << 1;
     118                 :            :                 int ret;
     119                 :            : 
     120         [ +  + ]:       8885 :                 if (new_size > PIPE_MAX_SIZE)
     121                 :            :                         return 1;
     122                 :            : 
     123                 :       7653 :                 ret = fcntl(ppb->p[0], F_SETPIPE_SZ, new_size * PAGE_SIZE);
     124         [ +  - ]:       7653 :                 if (ret < 0)
     125                 :            :                         return 1; /* need to add another buf */
     126                 :            : 
     127                 :       7653 :                 ret /= PAGE_SIZE;
     128         [ -  + ]:       7653 :                 BUG_ON(ret < ppb->pipe_size);
     129                 :            : 
     130                 :       7653 :                 pr_debug("Grow pipe %x -> %x\n", ppb->pipe_size, ret);
     131                 :       7653 :                 ppb->pipe_size = ret;
     132                 :            :         }
     133                 :            : 
     134         [ +  + ]:     690752 :         if (ppb->nr_segs) {
     135                 :            :                 /* can existing iov accumulate the page? */
     136                 :     685830 :                 iov = &ppb->iov[ppb->nr_segs - 1];
     137         [ +  + ]:     685830 :                 if ((unsigned long)iov->iov_base + iov->iov_len == addr) {
     138                 :     567816 :                         iov->iov_len += PAGE_SIZE;
     139                 :            :                         goto out;
     140                 :            :                 }
     141                 :            : 
     142         [ +  - ]:     118014 :                 if (ppb->nr_segs == UIO_MAXIOV)
     143                 :            :                         /* XXX -- shrink pipe back? */
     144                 :            :                         return 1;
     145                 :            :         }
     146                 :            : 
     147                 :     122936 :         pr_debug("Add iov to page pipe (%u iovs, %u/%u total)\n",
     148                 :            :                         ppb->nr_segs, pp->free_iov, pp->nr_iovs);
     149                 :     122936 :         ppb->iov[ppb->nr_segs].iov_base = (void *)addr;
     150                 :     122936 :         ppb->iov[ppb->nr_segs].iov_len = PAGE_SIZE;
     151                 :     122936 :         ppb->nr_segs++;
     152                 :     122936 :         pp->free_iov++;
     153         [ -  + ]:     122936 :         BUG_ON(pp->free_iov > pp->nr_iovs);
     154                 :            : out:
     155                 :     690752 :         ppb->pages_in++;
     156                 :            :         return 0;
     157                 :            : }
     158                 :            : 
     159                 :     691984 : static inline int try_add_page(struct page_pipe *pp, unsigned long addr)
     160                 :            : {
     161         [ -  + ]:     691984 :         BUG_ON(list_empty(&pp->bufs));
     162                 :     691984 :         return try_add_page_to(pp, list_entry(pp->bufs.prev, struct page_pipe_buf, l), addr);
     163                 :            : }
     164                 :            : 
     165                 :     690752 : int page_pipe_add_page(struct page_pipe *pp, unsigned long addr)
     166                 :            : {
     167                 :            :         int ret;
     168                 :            : 
     169                 :     690752 :         ret = try_add_page(pp, addr);
     170         [ +  + ]:     690752 :         if (ret <= 0)
     171                 :            :                 return ret;
     172                 :            : 
     173                 :       1232 :         ret = page_pipe_grow(pp);
     174         [ +  - ]:       1232 :         if (ret < 0)
     175                 :            :                 return ret;
     176                 :            : 
     177                 :       1232 :         ret = try_add_page(pp, addr);
     178         [ -  + ]:       1232 :         BUG_ON(ret > 0);
     179                 :       1232 :         return ret;
     180                 :            : }
     181                 :            : 
     182                 :            : #define PP_HOLES_BATCH  32
     183                 :            : 
     184                 :    1658317 : int page_pipe_add_hole(struct page_pipe *pp, unsigned long addr)
     185                 :            : {
     186                 :            :         struct iovec *iov;
     187                 :            : 
     188         [ +  + ]:    1658317 :         if (pp->free_hole >= pp->nr_holes) {
     189         [ -  + ]:       2872 :                 pp->holes = xrealloc(pp->holes,
     190                 :            :                                 (pp->nr_holes + PP_HOLES_BATCH) * sizeof(struct iovec));
     191         [ +  - ]:       2872 :                 if (!pp->holes)
     192                 :            :                         return -1;
     193                 :            : 
     194                 :       2872 :                 pp->nr_holes += PP_HOLES_BATCH;
     195                 :            :         }
     196                 :            : 
     197         [ +  + ]:    1658317 :         if (pp->free_hole) {
     198                 :    1655577 :                 iov = &pp->holes[pp->free_hole - 1];
     199         [ +  + ]:    1655577 :                 if ((unsigned long)iov->iov_base + iov->iov_len == addr) {
     200                 :    1627586 :                         iov->iov_len += PAGE_SIZE;
     201                 :    1627586 :                         goto out;
     202                 :            :                 }
     203                 :            :         }
     204                 :            : 
     205                 :      30731 :         iov = &pp->holes[pp->free_hole];
     206                 :      30731 :         iov->iov_base = (void *)addr;
     207                 :      30731 :         iov->iov_len = PAGE_SIZE;
     208                 :      30731 :         pp->free_hole++;
     209                 :            : out:
     210                 :            :         return 0;
     211                 :            : }
     212                 :            : 
     213                 :       3664 : void debug_show_page_pipe(struct page_pipe *pp)
     214                 :            : {
     215                 :            :         struct page_pipe_buf *ppb;
     216                 :            :         int i;
     217                 :            :         struct iovec *iov;
     218                 :            : 
     219         [ +  - ]:       3664 :         if (log_get_loglevel() < LOG_DEBUG)
     220                 :       3664 :                 return;
     221                 :            : 
     222                 :       3664 :         pr_debug("Page pipe:\n");
     223                 :       3664 :         pr_debug("* %u pipes %u/%u iovs:\n",
     224                 :            :                         pp->nr_pipes, pp->free_iov, pp->nr_iovs);
     225         [ +  + ]:       8560 :         list_for_each_entry(ppb, &pp->bufs, l) {
     226                 :       4896 :                 pr_debug("\tbuf %u pages, %u iovs:\n",
     227                 :            :                                 ppb->pages_in, ppb->nr_segs);
     228         [ +  + ]:     127794 :                 for (i = 0; i < ppb->nr_segs; i++) {
     229                 :     122898 :                         iov = &ppb->iov[i];
     230                 :     122898 :                         pr_debug("\t\t%p %lu\n", iov->iov_base, iov->iov_len / PAGE_SIZE);
     231                 :            :                 }
     232                 :            :         }
     233                 :            : 
     234                 :       3664 :         pr_debug("* %u holes:\n", pp->free_hole);
     235         [ +  + ]:      34395 :         for (i = 0; i < pp->free_hole; i++) {
     236                 :      30731 :                 iov = &pp->holes[i];
     237                 :      30731 :                 pr_debug("\t%p %lu\n", iov->iov_base, iov->iov_len / PAGE_SIZE);
     238                 :            :         }
     239                 :            : }

Generated by: LCOV version 1.9