LCOV - code coverage report
Current view: top level - home/snorch/criu - kerndat.c (source / functions) Hit Total Coverage
Test: coverage3.info Lines: 63 91 69.2 %
Date: 2014-04-22 Functions: 8 8 100.0 %
Branches: 19 40 47.5 %

           Branch data     Line data    Source code
       1                 :            : #include <unistd.h>
       2                 :            : #include <fcntl.h>
       3                 :            : #include <stdio.h>
       4                 :            : #include <sys/stat.h>
       5                 :            : #include <sys/types.h>
       6                 :            : #include <sys/mman.h>
       7                 :            : #include <errno.h>
       8                 :            : 
       9                 :            : #include "log.h"
      10                 :            : #include "bug.h"
      11                 :            : #include "kerndat.h"
      12                 :            : #include "fs-magic.h"
      13                 :            : #include "mem.h"
      14                 :            : #include "compiler.h"
      15                 :            : #include "sysctl.h"
      16                 :            : #include "asm/types.h"
      17                 :            : #include "cr_options.h"
      18                 :            : #include "util.h"
      19                 :            : 
      20                 :            : dev_t kerndat_shmem_dev;
      21                 :            : 
      22                 :            : /*
      23                 :            :  * Anonymous shared mappings are backed by hidden tmpfs
      24                 :            :  * mount. Find out its dev to distinguish such mappings
      25                 :            :  * from real tmpfs files maps.
      26                 :            :  */
      27                 :            : 
      28                 :       1792 : static int kerndat_get_shmemdev(void)
      29                 :            : {
      30                 :            :         void *map;
      31                 :            :         char maps[128];
      32                 :            :         struct stat buf;
      33                 :            : 
      34                 :       1792 :         map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
      35                 :            :                         MAP_SHARED | MAP_ANONYMOUS, 0, 0);
      36         [ -  + ]:       1792 :         if (map == MAP_FAILED) {
      37                 :          0 :                 pr_perror("Can't mmap memory for shmemdev test");
      38                 :          0 :                 return -1;
      39                 :            :         }
      40                 :            : 
      41                 :       1792 :         sprintf(maps, "/proc/self/map_files/%lx-%lx",
      42                 :       1792 :                         (unsigned long)map, (unsigned long)map + PAGE_SIZE);
      43         [ -  + ]:       1792 :         if (stat(maps, &buf) < 0) {
      44                 :          0 :                 munmap(map, PAGE_SIZE);
      45                 :          0 :                 pr_perror("Can't stat self map_files");
      46                 :          0 :                 return -1;
      47                 :            :         }
      48                 :            : 
      49                 :       1792 :         munmap(map, PAGE_SIZE);
      50                 :            : 
      51                 :       1792 :         kerndat_shmem_dev = buf.st_dev;
      52                 :       1792 :         pr_info("Found anon-shmem device at %"PRIx64"\n", kerndat_shmem_dev);
      53                 :       1792 :         return 0;
      54                 :            : }
      55                 :            : 
      56                 :        210 : struct stat *kerndat_get_devpts_stat()
      57                 :            : {
      58                 :            :         static struct stat st = {};
      59                 :            :         struct statfs fst;
      60                 :            : 
      61         [ +  - ]:        210 :         if (st.st_dev != 0)
      62                 :            :                 return &st;
      63                 :            : 
      64         [ -  + ]:        210 :         if (statfs("/dev/pts", &fst)) {
      65                 :          0 :                 pr_perror("Unable to statefs /dev/pts");
      66                 :          0 :                 return NULL;
      67                 :            :         }
      68         [ -  + ]:        210 :         if (fst.f_type != DEVPTS_SUPER_MAGIC) {
      69                 :          0 :                 pr_err("devpts isn't mount on the host\n");
      70                 :          0 :                 return NULL;
      71                 :            :         }
      72                 :            : 
      73                 :            :         /* The root /dev/pts is mounted w/o newinstance, isn't it? */
      74         [ -  + ]:        210 :         if (stat("/dev/pts", &st)) {
      75                 :          0 :                 pr_perror("Unable to stat /dev/pts");
      76                 :          0 :                 return NULL;
      77                 :            :         }
      78                 :            : 
      79                 :            :         return &st;
      80                 :            : }
      81                 :            : 
      82                 :            : /*
      83                 :            :  * Check whether pagemap reports soft dirty bit. Kernel has
      84                 :            :  * this functionality under CONFIG_MEM_SOFT_DIRTY option.
      85                 :            :  */
      86                 :            : 
      87                 :            : bool kerndat_has_dirty_track = false;
      88                 :            : 
      89                 :       1794 : int kerndat_get_dirty_track(void)
      90                 :            : {
      91                 :            :         char *map;
      92                 :            :         int pm2;
      93                 :       1794 :         u64 pmap = 0;
      94                 :            :         int ret = -1;
      95                 :            : 
      96                 :       1794 :         map = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE,
      97                 :            :                         MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
      98         [ -  + ]:       1794 :         if (map == MAP_FAILED) {
      99                 :          0 :                 pr_perror("Can't mmap memory for pagemap test");
     100                 :          0 :                 return ret;
     101                 :            :         }
     102                 :            : 
     103                 :            :         /*
     104                 :            :          * Kernel shows soft-dirty bits only if this soft-dirty
     105                 :            :          * was at least once re-set. (this is to be removed in
     106                 :            :          * a couple of kernel releases)
     107                 :            :          */
     108                 :       1794 :         do_task_reset_dirty_track(getpid());
     109                 :            :         pm2 = open("/proc/self/pagemap", O_RDONLY);
     110         [ -  + ]:       1794 :         if (pm2 < 0) {
     111                 :          0 :                 pr_perror("Can't open pagemap file");
     112                 :          0 :                 munmap(map, PAGE_SIZE);
     113                 :          0 :                 return ret;
     114                 :            :         }
     115                 :            : 
     116                 :       1794 :         map[0] = '\0';
     117                 :            : 
     118                 :       1794 :         lseek(pm2, (unsigned long)map / PAGE_SIZE * sizeof(u64), SEEK_SET);
     119                 :       1794 :         ret = read(pm2, &pmap, sizeof(pmap));
     120         [ -  + ]:       1794 :         if (ret < 0)
     121                 :          0 :                 pr_perror("Read pmap err!");
     122                 :            : 
     123                 :       1794 :         close(pm2);
     124                 :       1794 :         munmap(map, PAGE_SIZE);
     125                 :            : 
     126         [ +  - ]:       1794 :         if (pmap & PME_SOFT_DIRTY) {
     127                 :       1794 :                 pr_info("Dirty track supported on kernel\n");
     128                 :       1794 :                 kerndat_has_dirty_track = true;
     129                 :            :         } else {
     130                 :          0 :                 pr_info("Dirty tracking support is OFF\n");
     131         [ #  # ]:          0 :                 if (opts.track_mem) {
     132                 :          0 :                         pr_err("Tracking memory is not available\n");
     133                 :          0 :                         return -1;
     134                 :            :                 }
     135                 :            :         }
     136                 :            : 
     137                 :            :         return 0;
     138                 :            : }
     139                 :            : 
     140                 :            : /*
     141                 :            :  * Strictly speaking, if there is a machine with huge amount
     142                 :            :  * of memory, we're allowed to send up to 4M and read up to
     143                 :            :  * 6M of tcp data at once. But we will figure out precise size
     144                 :            :  * of a limit a bit later when restore starts.
     145                 :            :  *
     146                 :            :  * Meanwhile set it up to 2M and 3M, which is safe enough to
     147                 :            :  * proceed without errors.
     148                 :            :  */
     149                 :            : int tcp_max_wshare = 2U << 20;
     150                 :            : int tcp_max_rshare = 3U << 20;
     151                 :            : 
     152                 :       1013 : static int tcp_read_sysctl_limits(void)
     153                 :            : {
     154                 :       1013 :         u32 vect[2][3] = { };
     155                 :            :         int ret;
     156                 :            : 
     157                 :       1013 :         struct sysctl_req req[] = {
     158                 :            :                 { "net/ipv4/tcp_wmem", &vect[0], CTL_U32A(ARRAY_SIZE(vect[0])) },
     159                 :            :                 { "net/ipv4/tcp_rmem", &vect[1], CTL_U32A(ARRAY_SIZE(vect[1])) },
     160                 :            :                 { },
     161                 :            :         };
     162                 :            : 
     163                 :            :         /*
     164                 :            :          * Lets figure out which exactly amount of memory is
     165                 :            :          * availabe for send/read queues on restore.
     166                 :            :          */
     167                 :       1013 :         ret = sysctl_op(req, CTL_READ);
     168         [ -  + ]:       1013 :         if (ret) {
     169                 :          0 :                 pr_warn("TCP mem sysctls are not available. Using defaults.\n");
     170                 :          0 :                 goto out;
     171                 :            :         }
     172                 :            : 
     173                 :       1013 :         tcp_max_wshare = min(tcp_max_wshare, (int)vect[0][2]);
     174                 :       1013 :         tcp_max_rshare = min(tcp_max_rshare, (int)vect[1][2]);
     175                 :            : 
     176 [ +  - ][ -  + ]:       1013 :         if (tcp_max_wshare < 128 || tcp_max_rshare < 128)
     177                 :          0 :                 pr_warn("The memory limits for TCP queues are suspiciously small\n");
     178                 :            : out:
     179                 :       1013 :         pr_debug("TCP queue memory limits are %d:%d\n", tcp_max_wshare, tcp_max_rshare);
     180                 :       1013 :         return 0;
     181                 :            : }
     182                 :            : 
     183                 :            : /* The page frame number (PFN) is constant for the zero page */
     184                 :            : u64 zero_page_pfn;
     185                 :            : 
     186                 :       1792 : static int init_zero_page_pfn()
     187                 :            : {
     188                 :            :         void *addr;
     189                 :            :         int ret;
     190                 :            : 
     191                 :       1792 :         addr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     192         [ -  + ]:       1792 :         if (addr == MAP_FAILED) {
     193                 :          0 :                 pr_perror("Unable to map zero page");
     194                 :          0 :                 return 0;
     195                 :            :         }
     196                 :            : 
     197         [ -  + ]:       1792 :         if (*((int *) addr) != 0) {
     198                 :          0 :                 BUG();
     199                 :          0 :                 return -1;
     200                 :            :         }
     201                 :            : 
     202                 :       1792 :         ret = vaddr_to_pfn((unsigned long)addr, &zero_page_pfn);
     203                 :       1792 :         munmap(addr, PAGE_SIZE);
     204                 :            : 
     205         [ -  + ]:       1792 :         if (zero_page_pfn == 0)
     206                 :            :                 ret = -1;
     207                 :            : 
     208                 :       1792 :         return ret;
     209                 :            : }
     210                 :            : 
     211                 :       1792 : int kerndat_init(void)
     212                 :            : {
     213                 :            :         int ret;
     214                 :            : 
     215                 :       1792 :         ret = kerndat_get_shmemdev();
     216         [ +  - ]:       1792 :         if (!ret)
     217                 :       1792 :                 ret = kerndat_get_dirty_track();
     218         [ +  - ]:       1792 :         if (!ret)
     219                 :       1792 :                 ret = init_zero_page_pfn();
     220                 :            : 
     221                 :       1792 :         return ret;
     222                 :            : }
     223                 :            : 
     224                 :            : int kern_last_cap;
     225                 :            : 
     226                 :       1013 : int get_last_cap(void)
     227                 :            : {
     228                 :       1013 :         struct sysctl_req req[] = {
     229                 :            :                 { "kernel/cap_last_cap", &kern_last_cap, CTL_U32 },
     230                 :            :                 { },
     231                 :            :         };
     232                 :            : 
     233                 :       1013 :         return sysctl_op(req, CTL_READ);
     234                 :            : }
     235                 :            : 
     236                 :       1013 : int kerndat_init_rst(void)
     237                 :            : {
     238                 :            :         int ret;
     239                 :            : 
     240                 :            :         /*
     241                 :            :          * Read TCP sysctls before anything else,
     242                 :            :          * since the limits we're interested in are
     243                 :            :          * not available inside namespaces.
     244                 :            :          */
     245                 :            : 
     246                 :       1013 :         ret = tcp_read_sysctl_limits();
     247         [ +  - ]:       1013 :         if (!ret)
     248                 :       1013 :                 ret = get_last_cap();
     249                 :            : 
     250                 :       1013 :         return ret;
     251                 :            : }

Generated by: LCOV version 1.9