LCOV - code coverage report
Current view: top level - home/snorch/criu - page-xfer.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 226 282 80.1 %
Date: 2014-04-22 Functions: 22 22 100.0 %
Branches: 111 175 63.4 %

           Branch data     Line data    Source code
       1                 :            : #include <sys/socket.h>
       2                 :            : #include <netinet/in.h>
       3                 :            : #include <arpa/inet.h>
       4                 :            : #include <linux/falloc.h>
       5                 :            : #include <unistd.h>
       6                 :            : #include <fcntl.h>
       7                 :            : 
       8                 :            : #include "cr_options.h"
       9                 :            : #include "servicefd.h"
      10                 :            : #include "image.h"
      11                 :            : #include "page-xfer.h"
      12                 :            : #include "page-pipe.h"
      13                 :            : 
      14                 :            : #include "protobuf.h"
      15                 :            : #include "protobuf/pagemap.pb-c.h"
      16                 :            : 
      17                 :            : struct page_server_iov {
      18                 :            :         u32     cmd;
      19                 :            :         u32     nr_pages;
      20                 :            :         u64     vaddr;
      21                 :            :         u64     dst_id;
      22                 :            : };
      23                 :            : 
      24                 :            : static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id);
      25                 :            : 
      26                 :            : #define PS_IOV_ADD      1
      27                 :            : #define PS_IOV_HOLE     2
      28                 :            : #define PS_IOV_OPEN     3
      29                 :            : 
      30                 :            : #define PS_IOV_FLUSH            0x1023
      31                 :            : 
      32                 :            : #define PS_TYPE_BITS    8
      33                 :            : #define PS_TYPE_MASK    ((1 << PS_TYPE_BITS) - 1)
      34                 :            : 
      35                 :            : static inline u64 encode_pm_id(int type, long id)
      36                 :            : {
      37                 :       1854 :         return ((u64)id) << PS_TYPE_BITS | type;
      38                 :            : }
      39                 :            : 
      40                 :            : static int decode_pm_type(u64 dst_id)
      41                 :            : {
      42                 :       1854 :         return dst_id & PS_TYPE_MASK;
      43                 :            : }
      44                 :            : 
      45                 :            : static long decode_pm_id(u64 dst_id)
      46                 :            : {
      47                 :       1854 :         return (long)(dst_id >> PS_TYPE_BITS);
      48                 :            : }
      49                 :            : 
      50                 :            : struct page_xfer_job {
      51                 :            :         u64     dst_id;
      52                 :            :         int     p[2];
      53                 :            :         unsigned pipe_size;
      54                 :            :         struct page_xfer loc_xfer;
      55                 :            : };
      56                 :            : 
      57                 :            : static struct page_xfer_job cxfer = {
      58                 :            :         .dst_id = ~0,
      59                 :            : };
      60                 :            : 
      61                 :            : static void page_server_close(void)
      62                 :            : {
      63 [ +  + ][ +  - ]:       2750 :         if (cxfer.dst_id != ~0)
      64                 :       1854 :                 cxfer.loc_xfer.close(&cxfer.loc_xfer);
      65                 :            : }
      66                 :            : 
      67                 :       3708 : static int page_server_open(struct page_server_iov *pi)
      68                 :            : {
      69                 :            :         int type;
      70                 :            :         long id;
      71                 :            : 
      72                 :       1854 :         type = decode_pm_type(pi->dst_id);
      73                 :            :         id = decode_pm_id(pi->dst_id);
      74                 :       1854 :         pr_info("Opening %d/%ld\n", type, id);
      75                 :            : 
      76                 :            :         page_server_close();
      77                 :            : 
      78         [ +  - ]:       1854 :         if (open_page_local_xfer(&cxfer.loc_xfer, type, id))
      79                 :            :                 return -1;
      80                 :            : 
      81                 :       1854 :         cxfer.dst_id = pi->dst_id;
      82                 :            :         return 0;
      83                 :            : }
      84                 :            : 
      85                 :      76880 : static int prep_loc_xfer(struct page_server_iov *pi)
      86                 :            : {
      87         [ -  + ]:      76880 :         if (cxfer.dst_id != pi->dst_id) {
      88                 :          0 :                 pr_warn("Deprecated IO w/o open\n");
      89                 :          0 :                 return page_server_open(pi);
      90                 :            :         } else
      91                 :            :                 return 0;
      92                 :            : }
      93                 :            : 
      94                 :      61566 : static int page_server_add(int sk, struct page_server_iov *pi)
      95                 :            : {
      96                 :            :         size_t len;
      97                 :            :         struct page_xfer *lxfer = &cxfer.loc_xfer;
      98                 :            :         struct iovec iov;
      99                 :            : 
     100                 :      61566 :         pr_debug("Adding %"PRIx64"/%u\n", pi->vaddr, pi->nr_pages);
     101                 :            : 
     102         [ +  - ]:      61566 :         if (prep_loc_xfer(pi))
     103                 :            :                 return -1;
     104                 :            : 
     105                 :     123132 :         iov.iov_base = decode_pointer(pi->vaddr);
     106                 :      61566 :         iov.iov_len = pi->nr_pages * PAGE_SIZE;
     107                 :            : 
     108         [ +  - ]:      61566 :         if (lxfer->write_pagemap(lxfer, &iov))
     109                 :            :                 return -1;
     110                 :            : 
     111                 :      61566 :         len = iov.iov_len;
     112         [ +  + ]:     140460 :         while (len > 0) {
     113                 :            :                 ssize_t chunk;
     114                 :            : 
     115                 :      78894 :                 chunk = len;
     116         [ +  + ]:      78894 :                 if (chunk > cxfer.pipe_size)
     117                 :            :                         chunk = cxfer.pipe_size;
     118                 :            : 
     119                 :      78894 :                 chunk = splice(sk, NULL, cxfer.p[1], NULL, chunk, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
     120         [ -  + ]:      78894 :                 if (chunk < 0) {
     121                 :          0 :                         pr_perror("Can't read from socket");
     122                 :          0 :                         return -1;
     123                 :            :                 }
     124                 :            : 
     125         [ +  - ]:      78894 :                 if (lxfer->write_pages(lxfer, cxfer.p[0], chunk))
     126                 :            :                         return -1;
     127                 :            : 
     128                 :      78894 :                 len -= chunk;
     129                 :            :         }
     130                 :            : 
     131                 :            :         return 0;
     132                 :            : }
     133                 :            : 
     134                 :      30628 : static int page_server_hole(int sk, struct page_server_iov *pi)
     135                 :            : {
     136                 :            :         struct page_xfer *lxfer = &cxfer.loc_xfer;
     137                 :            :         struct iovec iov;
     138                 :            : 
     139                 :      15314 :         pr_debug("Adding %"PRIx64"/%u hole\n", pi->vaddr, pi->nr_pages);
     140                 :            : 
     141         [ +  - ]:      15314 :         if (prep_loc_xfer(pi))
     142                 :            :                 return -1;
     143                 :            : 
     144                 :      30628 :         iov.iov_base = decode_pointer(pi->vaddr);
     145                 :      15314 :         iov.iov_len = pi->nr_pages * PAGE_SIZE;
     146                 :            : 
     147         [ +  - ]:      15314 :         if (lxfer->write_hole(lxfer, &iov))
     148                 :            :                 return -1;
     149                 :            : 
     150                 :            :         return 0;
     151                 :            : }
     152                 :            : 
     153                 :        896 : static int page_server_serve(int sk)
     154                 :            : {
     155                 :            :         int ret = -1;
     156                 :            :         bool flushed = false;
     157                 :            : 
     158         [ -  + ]:        896 :         if (pipe(cxfer.p)) {
     159                 :          0 :                 pr_perror("Can't make pipe for xfer");
     160                 :          0 :                 close(sk);
     161                 :          0 :                 return -1;
     162                 :            :         }
     163                 :            : 
     164                 :        896 :         cxfer.pipe_size = fcntl(cxfer.p[0], F_GETPIPE_SZ, 0);
     165                 :        896 :         pr_debug("Created xfer pipe size %u\n", cxfer.pipe_size);
     166                 :            : 
     167                 :            :         while (1) {
     168                 :            :                 struct page_server_iov pi;
     169                 :            : 
     170                 :      80526 :                 ret = recv(sk, &pi, sizeof(pi), MSG_WAITALL);
     171         [ +  + ]:      80526 :                 if (!ret)
     172                 :            :                         break;
     173                 :            : 
     174         [ -  + ]:      79630 :                 if (ret != sizeof(pi)) {
     175                 :          0 :                         pr_perror("Can't read pagemap from socket");
     176                 :            :                         ret = -1;
     177                 :          0 :                         break;
     178                 :            :                 }
     179                 :            : 
     180                 :            :                 flushed = false;
     181                 :            : 
     182   [ +  +  +  +  :      79630 :                 switch (pi.cmd) {
                      - ]
     183                 :            :                 case PS_IOV_OPEN:
     184                 :       1854 :                         ret = page_server_open(&pi);
     185                 :       1854 :                         break;
     186                 :            :                 case PS_IOV_ADD:
     187                 :      61566 :                         ret = page_server_add(sk, &pi);
     188                 :      61566 :                         break;
     189                 :            :                 case PS_IOV_HOLE:
     190                 :      15314 :                         ret = page_server_hole(sk, &pi);
     191                 :      15314 :                         break;
     192                 :            :                 case PS_IOV_FLUSH:
     193                 :            :                 {
     194                 :        896 :                         int32_t status = 0;
     195                 :            : 
     196                 :            :                         /*
     197                 :            :                          * An answer must be sent back to inform another side,
     198                 :            :                          * that all data were received
     199                 :            :                          */
     200         [ -  + ]:        896 :                         if (write(sk, &status, sizeof(status)) != sizeof(status)) {
     201                 :        896 :                                 pr_perror("Can't send the final package");
     202                 :            :                                 ret = -1;
     203                 :            :                         }
     204                 :            : 
     205                 :            :                         flushed = true;
     206                 :            :                         ret = 0;
     207                 :            :                         break;
     208                 :            :                 }
     209                 :            :                 default:
     210                 :          0 :                         pr_err("Unknown command %u\n", pi.cmd);
     211                 :            :                         ret = -1;
     212                 :          0 :                         break;
     213                 :            :                 }
     214                 :            : 
     215         [ +  - ]:      79630 :                 if (ret)
     216                 :            :                         break;
     217                 :      79630 :         }
     218                 :            : 
     219         [ -  + ]:        896 :         if (!ret && !flushed) {
     220                 :          0 :                 pr_err("The data were not flushed\n");
     221                 :            :                 ret = -1;
     222                 :            :         }
     223                 :            : 
     224                 :            :         page_server_close();
     225                 :        896 :         pr_info("Session over\n");
     226                 :            : 
     227                 :        896 :         close(sk);
     228                 :        896 :         return ret;
     229                 :            : }
     230                 :            : 
     231                 :       1792 : static int get_sockaddr_in(struct sockaddr_in *addr)
     232                 :            : {
     233                 :            :         memset(addr, 0, sizeof(*addr));
     234                 :       1792 :         addr->sin_family = AF_INET;
     235                 :            : 
     236         [ +  + ]:       1792 :         if (!opts.addr)
     237                 :        896 :                 addr->sin_addr.s_addr = INADDR_ANY;
     238         [ -  + ]:        896 :         else if (!inet_aton(opts.addr, &addr->sin_addr)) {
     239                 :          0 :                 pr_perror("Bad page server address");
     240                 :          0 :                 return -1;
     241                 :            :         }
     242                 :            : 
     243                 :       1792 :         addr->sin_port = opts.ps_port;
     244                 :       1792 :         return 0;
     245                 :            : }
     246                 :            : 
     247                 :        896 : int cr_page_server(bool daemon_mode)
     248                 :            : {
     249                 :            :         int sk, ask = -1, ret;
     250                 :            :         struct sockaddr_in saddr, caddr;
     251                 :        896 :         socklen_t clen = sizeof(caddr);
     252                 :            : 
     253                 :        896 :         up_page_ids_base();
     254                 :            : 
     255         [ -  + ]:        896 :         pr_info("Starting page server on port %u\n", (int)ntohs(opts.ps_port));
     256                 :            : 
     257                 :        896 :         sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
     258         [ -  + ]:        896 :         if (sk < 0) {
     259                 :          0 :                 pr_perror("Can't init page server");
     260                 :          0 :                 return -1;
     261                 :            :         }
     262                 :            : 
     263         [ +  - ]:        896 :         if (get_sockaddr_in(&saddr))
     264                 :            :                 goto out;
     265                 :            : 
     266         [ -  + ]:        896 :         if (bind(sk, (struct sockaddr *)&saddr, sizeof(saddr))) {
     267                 :          0 :                 pr_perror("Can't bind page server");
     268                 :          0 :                 goto out;
     269                 :            :         }
     270                 :            : 
     271         [ -  + ]:        896 :         if (listen(sk, 1)) {
     272                 :          0 :                 pr_perror("Can't listen on page server socket");
     273                 :          0 :                 goto out;
     274                 :            :         }
     275                 :            : 
     276         [ +  - ]:        896 :         if (daemon_mode) {
     277                 :        896 :                 ret = cr_daemon(1, 0);
     278         [ -  + ]:       1792 :                 if (ret == -1) {
     279                 :          0 :                         pr_perror("Can't run in the background");
     280                 :          0 :                         goto out;
     281                 :            :                 }
     282         [ +  + ]:       1792 :                 if (ret > 0) /* parent task, daemon started */
     283                 :            :                         return ret;
     284                 :            :         }
     285                 :            : 
     286         [ -  + ]:        896 :         if (opts.pidfile) {
     287         [ #  # ]:          0 :                 if (write_pidfile(getpid()) == -1) {
     288                 :          0 :                         pr_perror("Can't write pidfile");
     289                 :          0 :                         return -1;
     290                 :            :                 }
     291                 :            :         }
     292                 :            : 
     293                 :        896 :         ret = ask = accept(sk, (struct sockaddr *)&caddr, &clen);
     294         [ -  + ]:        896 :         if (ask < 0)
     295                 :          0 :                 pr_perror("Can't accept connection to server");
     296                 :            : 
     297                 :        896 :         close(sk);
     298                 :            : 
     299         [ +  - ]:        896 :         if (ask >= 0) {
     300         [ -  + ]:        896 :                 pr_info("Accepted connection from %s:%u\n",
     301                 :            :                                 inet_ntoa(caddr.sin_addr),
     302                 :            :                                 (int)ntohs(caddr.sin_port));
     303                 :            : 
     304                 :        896 :                 ret = page_server_serve(ask);
     305                 :            :         }
     306                 :            : 
     307         [ +  - ]:        896 :         if (daemon_mode)
     308                 :        896 :                 exit(ret);
     309                 :            : 
     310                 :            :         return ret;
     311                 :            : 
     312                 :            : out:
     313                 :          0 :         close(sk);
     314                 :          0 :         return -1;
     315                 :            : }
     316                 :            : 
     317                 :            : static int page_server_sk = -1;
     318                 :            : 
     319                 :       1792 : int connect_to_page_server(void)
     320                 :            : {
     321                 :            :         struct sockaddr_in saddr;
     322                 :            : 
     323         [ +  + ]:       1792 :         if (!opts.use_page_server)
     324                 :            :                 return 0;
     325                 :            : 
     326         [ -  + ]:        896 :         pr_info("Connecting to server %s:%u\n",
     327                 :            :                         opts.addr, (int)ntohs(opts.ps_port));
     328                 :            : 
     329                 :        896 :         page_server_sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
     330         [ -  + ]:        896 :         if (page_server_sk < 0) {
     331                 :          0 :                 pr_perror("Can't create socket");
     332                 :          0 :                 return -1;
     333                 :            :         }
     334                 :            : 
     335         [ +  - ]:        896 :         if (get_sockaddr_in(&saddr))
     336                 :            :                 return -1;
     337                 :            : 
     338         [ -  + ]:        896 :         if (connect(page_server_sk, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
     339                 :          0 :                 pr_perror("Can't connect to server");
     340                 :          0 :                 return -1;
     341                 :            :         }
     342                 :            : 
     343                 :            :         return 0;
     344                 :            : }
     345                 :            : 
     346                 :       1792 : int disconnect_from_page_server(void)
     347                 :            : {
     348                 :       1792 :         struct page_server_iov pi = { .cmd = PS_IOV_FLUSH };
     349                 :       1792 :         int32_t status = -1;
     350                 :            :         int ret = -1;
     351                 :            : 
     352         [ +  + ]:       1792 :         if (!opts.use_page_server)
     353                 :            :                 return 0;
     354                 :            : 
     355         [ +  - ]:        896 :         if (page_server_sk == -1)
     356                 :            :                 return 0;
     357                 :            : 
     358         [ -  + ]:        896 :         pr_info("Disconnect from the page server %s:%u\n",
     359                 :            :                         opts.addr, (int)ntohs(opts.ps_port));
     360                 :            : 
     361         [ -  + ]:        896 :         if (write(page_server_sk, &pi, sizeof(pi)) != sizeof(pi)) {
     362                 :          0 :                 pr_perror("Can't write the fini command to server");
     363                 :          0 :                 goto out;
     364                 :            :         }
     365                 :            : 
     366         [ -  + ]:        896 :         if (read(page_server_sk, &status, sizeof(status)) != sizeof(status)) {
     367                 :          0 :                 pr_perror("The page server doesn't answer");
     368                 :          0 :                 goto out;
     369                 :            :         }
     370                 :            : 
     371                 :            :         ret = 0;
     372                 :            : out:
     373                 :        896 :         close_safe(&page_server_sk);
     374         [ +  - ]:        896 :         return ret ? : status;
     375                 :            : }
     376                 :            : 
     377                 :      61566 : static int write_pagemap_to_server(struct page_xfer *xfer,
     378                 :            :                 struct iovec *iov)
     379                 :            : {
     380                 :            :         struct page_server_iov pi;
     381                 :            : 
     382                 :      61566 :         pi.cmd = PS_IOV_ADD;
     383                 :      61566 :         pi.dst_id = xfer->dst_id;
     384                 :     123132 :         pi.vaddr = encode_pointer(iov->iov_base);
     385                 :      61566 :         pi.nr_pages = iov->iov_len / PAGE_SIZE;
     386                 :            : 
     387         [ -  + ]:      61566 :         if (write(xfer->fd, &pi, sizeof(pi)) != sizeof(pi)) {
     388                 :          0 :                 pr_perror("Can't write pagemap to server");
     389                 :          0 :                 return -1;
     390                 :            :         }
     391                 :            : 
     392                 :            :         return 0;
     393                 :            : }
     394                 :            : 
     395                 :      61566 : static int write_pages_to_server(struct page_xfer *xfer,
     396                 :            :                 int p, unsigned long len)
     397                 :            : {
     398                 :      61566 :         pr_debug("Splicing %lu bytes / %lu pages into socket\n", len, len / PAGE_SIZE);
     399                 :            : 
     400         [ -  + ]:      61566 :         if (splice(p, NULL, xfer->fd, NULL, len, SPLICE_F_MOVE) != len) {
     401                 :          0 :                 pr_perror("Can't write pages to socket");
     402                 :          0 :                 return -1;
     403                 :            :         }
     404                 :            : 
     405                 :            :         return 0;
     406                 :            : }
     407                 :            : 
     408                 :      15314 : static int write_hole_to_server(struct page_xfer *xfer, struct iovec *iov)
     409                 :            : {
     410                 :            :         struct page_server_iov pi;
     411                 :            : 
     412                 :      15314 :         pi.cmd = PS_IOV_HOLE;
     413                 :      15314 :         pi.dst_id = xfer->dst_id;
     414                 :      30628 :         pi.vaddr = encode_pointer(iov->iov_base);
     415                 :      15314 :         pi.nr_pages = iov->iov_len / PAGE_SIZE;
     416                 :            : 
     417         [ -  + ]:      15314 :         if (write(xfer->fd, &pi, sizeof(pi)) != sizeof(pi)) {
     418                 :          0 :                 pr_perror("Can't write pagehole to server");
     419                 :          0 :                 return -1;
     420                 :            :         }
     421                 :            : 
     422                 :            :         return 0;
     423                 :            : }
     424                 :            : 
     425                 :       1854 : static void close_server_xfer(struct page_xfer *xfer)
     426                 :            : {
     427                 :       1854 :         xfer->fd = -1;
     428                 :       1854 : }
     429                 :            : 
     430                 :       1854 : static int open_page_server_xfer(struct page_xfer *xfer, int fd_type, long id)
     431                 :            : {
     432                 :            :         struct page_server_iov pi;
     433                 :            : 
     434                 :       1854 :         xfer->fd = page_server_sk;
     435                 :       1854 :         xfer->write_pagemap = write_pagemap_to_server;
     436                 :       1854 :         xfer->write_pages = write_pages_to_server;
     437                 :       1854 :         xfer->write_hole = write_hole_to_server;
     438                 :       1854 :         xfer->close = close_server_xfer;
     439                 :       1854 :         xfer->dst_id = encode_pm_id(fd_type, id);
     440                 :            : 
     441                 :       1854 :         pi.cmd = PS_IOV_OPEN;
     442                 :       1854 :         pi.dst_id = xfer->dst_id;
     443                 :       1854 :         pi.vaddr = 0;
     444                 :       1854 :         pi.nr_pages = 0;
     445                 :            : 
     446         [ -  + ]:       1854 :         if (write(xfer->fd, &pi, sizeof(pi)) != sizeof(pi)) {
     447                 :          0 :                 pr_perror("Can't write to page server");
     448                 :          0 :                 return -1;
     449                 :            :         }
     450                 :            : 
     451                 :            :         return 0;
     452                 :            : }
     453                 :            : 
     454                 :     122936 : static int write_pagemap_loc(struct page_xfer *xfer,
     455                 :            :                 struct iovec *iov)
     456                 :            : {
     457                 :            :         int ret;
     458                 :     122936 :         PagemapEntry pe = PAGEMAP_ENTRY__INIT;
     459                 :            : 
     460                 :     245872 :         pe.vaddr = encode_pointer(iov->iov_base);
     461                 :     122936 :         pe.nr_pages = iov->iov_len / PAGE_SIZE;
     462                 :            : 
     463 [ +  - ][ +  + ]:     122936 :         if (opts.auto_dedup && xfer->parent != NULL) {
     464                 :      87464 :                 ret = dedup_one_iovec(xfer->parent, iov);
     465         [ -  + ]:      87464 :                 if (ret == -1) {
     466                 :          0 :                         pr_perror("Auto-deduplication failed");
     467                 :          0 :                         return ret;
     468                 :            :                 }
     469                 :            :         }
     470                 :     122936 :         return pb_write_one(xfer->fd, &pe, PB_PAGEMAP);
     471                 :            : }
     472                 :            : 
     473                 :     140264 : static int write_pages_loc(struct page_xfer *xfer,
     474                 :            :                 int p, unsigned long len)
     475                 :            : {
     476                 :            :         ssize_t ret;
     477                 :     140264 :         ret = splice(p, NULL, xfer->fd_pg, NULL, len, SPLICE_F_MOVE);
     478         [ -  + ]:     140264 :         if (ret == -1) {
     479                 :          0 :                 pr_perror("Unable to spice data");
     480                 :          0 :                 return -1;
     481                 :            :         }
     482         [ -  + ]:     140264 :         if (ret != len) {
     483                 :          0 :                 pr_err("Only %zu of %lu bytes have been spliced\n", ret, len);
     484                 :          0 :                 return -1;
     485                 :            :         }
     486                 :            : 
     487                 :            :         return 0;
     488                 :            : }
     489                 :            : 
     490                 :      30707 : static int check_pagehole_in_parent(struct page_read *p, struct iovec *iov)
     491                 :            : {
     492                 :            :         int ret;
     493                 :            :         unsigned long off, end;
     494                 :            : 
     495                 :            :         /*
     496                 :            :          * Try to find pagemap entry in parent, from which
     497                 :            :          * the data will be read on restore.
     498                 :            :          *
     499                 :            :          * This is the optimized version of the page-by-page
     500                 :            :          * read_pagemap_page routine.
     501                 :            :          */
     502                 :            : 
     503                 :      30707 :         pr_debug("Checking %p/%zu hole\n", iov->iov_base, iov->iov_len);
     504                 :      30707 :         off = (unsigned long)iov->iov_base;
     505                 :      30707 :         end = off + iov->iov_len;
     506                 :            :         while (1) {
     507                 :            :                 struct iovec piov;
     508                 :            :                 unsigned long pend;
     509                 :            : 
     510                 :      31795 :                 ret = seek_pagemap_page(p, off, true);
     511 [ +  - ][ +  - ]:      31795 :                 if (ret <= 0 || !p->pe)
     512                 :      30707 :                         return -1;
     513                 :            : 
     514                 :      31795 :                 pagemap2iovec(p->pe, &piov);
     515                 :      31795 :                 pr_debug("\tFound %p/%zu\n", piov.iov_base, piov.iov_len);
     516                 :            : 
     517                 :            :                 /*
     518                 :            :                  * The pagemap entry in parent may heppen to be
     519                 :            :                  * shorter, than the hole we write. In this case
     520                 :            :                  * we should go ahead and check the remainder.
     521                 :            :                  */
     522                 :            : 
     523                 :      31795 :                 pend = (unsigned long)piov.iov_base + piov.iov_len;
     524         [ +  + ]:      31795 :                 if (end <= pend)
     525                 :            :                         return 0;
     526                 :            : 
     527                 :       1088 :                 pr_debug("\t\tcontinue on %lx\n", pend);
     528                 :            :                 off = pend;
     529                 :       1088 :         }
     530                 :            : }
     531                 :            : 
     532                 :      30731 : static int write_pagehole_loc(struct page_xfer *xfer, struct iovec *iov)
     533                 :            : {
     534                 :      30731 :         PagemapEntry pe = PAGEMAP_ENTRY__INIT;
     535                 :            : 
     536         [ +  + ]:      30731 :         if (xfer->parent != NULL) {
     537                 :            :                 int ret;
     538                 :            : 
     539                 :      30707 :                 ret = check_pagehole_in_parent(xfer->parent, iov);
     540         [ -  + ]:      30707 :                 if (ret) {
     541                 :          0 :                         pr_err("Hole %p/%zu not found in parent\n",
     542                 :            :                                         iov->iov_base, iov->iov_len);
     543                 :          0 :                         return -1;
     544                 :            :                 }
     545                 :            :         }
     546                 :            : 
     547                 :      61462 :         pe.vaddr = encode_pointer(iov->iov_base);
     548                 :      30731 :         pe.nr_pages = iov->iov_len / PAGE_SIZE;
     549                 :      30731 :         pe.has_in_parent = true;
     550                 :      30731 :         pe.in_parent = true;
     551                 :            : 
     552         [ +  - ]:      30731 :         if (pb_write_one(xfer->fd, &pe, PB_PAGEMAP) < 0)
     553                 :            :                 return -1;
     554                 :            : 
     555                 :      30731 :         return 0;
     556                 :            : }
     557                 :            : 
     558                 :       3706 : static void close_page_xfer(struct page_xfer *xfer)
     559                 :            : {
     560         [ +  + ]:       3706 :         if (xfer->parent != NULL) {
     561                 :       2742 :                 xfer->parent->close(xfer->parent);
     562         [ +  - ]:       2742 :                 xfree(xfer->parent);
     563                 :       2742 :                 xfer->parent = NULL;
     564                 :            :         }
     565                 :       3706 :         close(xfer->fd_pg);
     566                 :       3706 :         close(xfer->fd);
     567                 :       3706 : }
     568                 :            : 
     569                 :       3706 : int page_xfer_dump_pages(struct page_xfer *xfer, struct page_pipe *pp,
     570                 :            :                 unsigned long off)
     571                 :            : {
     572                 :            :         struct page_pipe_buf *ppb;
     573                 :            :         struct iovec *hole = NULL;
     574                 :            : 
     575                 :       3706 :         pr_debug("Transfering pages:\n");
     576                 :            : 
     577         [ +  + ]:       3706 :         if (pp->free_hole)
     578                 :       2740 :                 hole = &pp->holes[0];
     579                 :            : 
     580         [ +  + ]:       8644 :         list_for_each_entry(ppb, &pp->bufs, l) {
     581                 :            :                 int i;
     582                 :            : 
     583                 :       4938 :                 pr_debug("\tbuf %d/%d\n", ppb->pages_in, ppb->nr_segs);
     584                 :            : 
     585         [ +  + ]:     127874 :                 for (i = 0; i < ppb->nr_segs; i++) {
     586                 :     122936 :                         struct iovec *iov = &ppb->iov[i];
     587                 :            : 
     588 [ +  + ][ +  + ]:     148069 :                         while (hole && (hole->iov_base < iov->iov_base)) {
     589                 :      25133 :                                 pr_debug("\th %p [%u]\n", hole->iov_base,
     590                 :            :                                                 (unsigned int)(hole->iov_len / PAGE_SIZE));
     591         [ +  - ]:      25133 :                                 if (xfer->write_hole(xfer, hole))
     592                 :            :                                         return -1;
     593                 :            : 
     594                 :      25133 :                                 hole++;
     595         [ -  + ]:      25133 :                                 if (hole >= &pp->holes[pp->free_hole])
     596                 :            :                                         hole = NULL;
     597                 :            :                         }
     598                 :            : 
     599         [ -  + ]:     122936 :                         BUG_ON(iov->iov_base < (void *)off);
     600                 :     122936 :                         iov->iov_base -= off;
     601                 :     122936 :                         pr_debug("\tp %p [%u]\n", iov->iov_base,
     602                 :            :                                         (unsigned int)(iov->iov_len / PAGE_SIZE));
     603                 :            : 
     604         [ +  - ]:     122936 :                         if (xfer->write_pagemap(xfer, iov))
     605                 :            :                                 return -1;
     606         [ +  - ]:     122936 :                         if (xfer->write_pages(xfer, ppb->p[0], iov->iov_len))
     607                 :            :                                 return -1;
     608                 :            :                 }
     609                 :            :         }
     610                 :            : 
     611         [ +  + ]:       9304 :         while (hole) {
     612                 :       5598 :                 pr_debug("\th* %p [%u]\n", hole->iov_base,
     613                 :            :                                 (unsigned int)(hole->iov_len / PAGE_SIZE));
     614         [ +  - ]:       5598 :                 if (xfer->write_hole(xfer, hole))
     615                 :            :                         return -1;
     616                 :            : 
     617                 :       5598 :                 hole++;
     618         [ +  + ]:       5598 :                 if (hole >= &pp->holes[pp->free_hole])
     619                 :            :                         hole = NULL;
     620                 :            :         }
     621                 :            : 
     622                 :            :         return 0;
     623                 :            : }
     624                 :            : 
     625                 :       3706 : static int open_page_local_xfer(struct page_xfer *xfer, int fd_type, long id)
     626                 :            : {
     627                 :       3706 :         xfer->fd = open_image(fd_type, O_DUMP, id);
     628         [ +  - ]:       3706 :         if (xfer->fd < 0)
     629                 :            :                 return -1;
     630                 :            : 
     631                 :       3706 :         xfer->fd_pg = open_pages_image(O_DUMP, xfer->fd);
     632         [ -  + ]:       3706 :         if (xfer->fd_pg < 0) {
     633                 :          0 :                 close(xfer->fd);
     634                 :          0 :                 return -1;
     635                 :            :         }
     636                 :            : 
     637                 :            :         /*
     638                 :            :          * Open page-read for parent images (if it exists). It will
     639                 :            :          * be used for two things:
     640                 :            :          * 1) when writing a page, those from parent will be dedup-ed
     641                 :            :          * 2) when writing a hole, the respective place would be checked
     642                 :            :          *    to exist in parent (either pagemap or hole)
     643                 :            :          */
     644                 :       3706 :         xfer->parent = NULL;
     645         [ +  + ]:       3706 :         if (fd_type == CR_FD_PAGEMAP) {
     646                 :            :                 int ret;
     647                 :            :                 int pfd;
     648                 :            : 
     649                 :       3664 :                 pfd = openat(get_service_fd(IMG_FD_OFF), CR_PARENT_LINK, O_RDONLY);
     650 [ +  + ][ -  + ]:       3664 :                 if (pfd < 0 && errno == ENOENT)
     651                 :            :                         goto out;
     652                 :            : 
     653         [ -  + ]:       2749 :                 xfer->parent = xmalloc(sizeof(*xfer->parent));
     654         [ -  + ]:       2749 :                 if (!xfer->parent) {
     655                 :          0 :                         close(pfd);
     656                 :          0 :                         return -1;
     657                 :            :                 }
     658                 :            : 
     659                 :       2749 :                 ret = open_page_read_at(pfd, id, xfer->parent, O_RDWR, false);
     660         [ +  + ]:       2749 :                 if (ret) {
     661                 :          7 :                         pr_perror("No parent image found, though parent directory is set");
     662         [ +  - ]:          7 :                         xfree(xfer->parent);
     663                 :          7 :                         xfer->parent = NULL;
     664                 :          7 :                         close(pfd);
     665                 :          7 :                         goto out;
     666                 :            :                 }
     667                 :       2742 :                 close(pfd);
     668                 :            :         }
     669                 :            : 
     670                 :            : out:
     671                 :       3706 :         xfer->write_pagemap = write_pagemap_loc;
     672                 :       3706 :         xfer->write_pages = write_pages_loc;
     673                 :       3706 :         xfer->write_hole = write_pagehole_loc;
     674                 :       3706 :         xfer->close = close_page_xfer;
     675                 :       3706 :         return 0;
     676                 :            : }
     677                 :            : 
     678                 :       3706 : int open_page_xfer(struct page_xfer *xfer, int fd_type, long id)
     679                 :            : {
     680         [ +  + ]:       3706 :         if (opts.use_page_server)
     681                 :       1854 :                 return open_page_server_xfer(xfer, fd_type, id);
     682                 :            :         else
     683                 :       1852 :                 return open_page_local_xfer(xfer, fd_type, id);
     684                 :            : }

Generated by: LCOV version 1.9