LCOV - code coverage report
Current view: top level - arch/um/os-Linux - mem.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 44 80 55.0 %
Date: 2022-12-09 01:23:36 Functions: 6 6 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
       4             :  */
       5             : 
       6             : #include <stdio.h>
       7             : #include <stddef.h>
       8             : #include <stdlib.h>
       9             : #include <unistd.h>
      10             : #include <errno.h>
      11             : #include <fcntl.h>
      12             : #include <string.h>
      13             : #include <sys/stat.h>
      14             : #include <sys/mman.h>
      15             : #include <sys/vfs.h>
      16             : #include <linux/magic.h>
      17             : #include <init.h>
      18             : #include <os.h>
      19             : 
      20             : /* Set by make_tempfile() during early boot. */
      21             : static char *tempdir = NULL;
      22             : 
      23             : /* Check if dir is on tmpfs. Return 0 if yes, -1 if no or error. */
      24           2 : static int __init check_tmpfs(const char *dir)
      25             : {
      26             :         struct statfs st;
      27             : 
      28           2 :         os_info("Checking if %s is on tmpfs...", dir);
      29           2 :         if (statfs(dir, &st) < 0) {
      30           0 :                 os_info("%s\n", strerror(errno));
      31           2 :         } else if (st.f_type != TMPFS_MAGIC) {
      32           0 :                 os_info("no\n");
      33             :         } else {
      34           2 :                 os_info("OK\n");
      35           2 :                 return 0;
      36             :         }
      37             :         return -1;
      38             : }
      39             : 
      40             : /*
      41             :  * Choose the tempdir to use. We want something on tmpfs so that our memory is
      42             :  * not subject to the host's vm.dirty_ratio. If a tempdir is specified in the
      43             :  * environment, we use that even if it's not on tmpfs, but we warn the user.
      44             :  * Otherwise, we try common tmpfs locations, and if no tmpfs directory is found
      45             :  * then we fall back to /tmp.
      46             :  */
      47           2 : static char * __init choose_tempdir(void)
      48             : {
      49             :         static const char * const vars[] = {
      50             :                 "TMPDIR",
      51             :                 "TMP",
      52             :                 "TEMP",
      53             :                 NULL
      54             :         };
      55             :         static const char fallback_dir[] = "/tmp";
      56             :         static const char * const tmpfs_dirs[] = {
      57             :                 "/dev/shm",
      58             :                 fallback_dir,
      59             :                 NULL
      60             :         };
      61             :         int i;
      62             :         const char *dir;
      63             : 
      64           2 :         os_info("Checking environment variables for a tempdir...");
      65           8 :         for (i = 0; vars[i]; i++) {
      66           6 :                 dir = getenv(vars[i]);
      67           6 :                 if ((dir != NULL) && (*dir != '\0')) {
      68           0 :                         os_info("%s\n", dir);
      69           0 :                         if (check_tmpfs(dir) >= 0)
      70             :                                 goto done;
      71             :                         else
      72             :                                 goto warn;
      73             :                 }
      74             :         }
      75           2 :         os_info("none found\n");
      76             : 
      77           2 :         for (i = 0; tmpfs_dirs[i]; i++) {
      78           2 :                 dir = tmpfs_dirs[i];
      79           2 :                 if (check_tmpfs(dir) >= 0)
      80             :                         goto done;
      81             :         }
      82             : 
      83             :         dir = fallback_dir;
      84             : warn:
      85           0 :         os_warn("Warning: tempdir %s is not on tmpfs\n", dir);
      86             : done:
      87             :         /* Make a copy since getenv results may not remain valid forever. */
      88           2 :         return strdup(dir);
      89             : }
      90             : 
      91             : /*
      92             :  * Create an unlinked tempfile in a suitable tempdir. template must be the
      93             :  * basename part of the template with a leading '/'.
      94             :  */
      95           4 : static int __init make_tempfile(const char *template)
      96             : {
      97             :         char *tempname;
      98             :         int fd;
      99             : 
     100           4 :         if (tempdir == NULL) {
     101           2 :                 tempdir = choose_tempdir();
     102           2 :                 if (tempdir == NULL) {
     103           0 :                         os_warn("Failed to choose tempdir: %s\n",
     104           0 :                                 strerror(errno));
     105           0 :                         return -1;
     106             :                 }
     107             :         }
     108             : 
     109             : #ifdef O_TMPFILE
     110           4 :         fd = open(tempdir, O_CLOEXEC | O_RDWR | O_EXCL | O_TMPFILE, 0700);
     111             :         /*
     112             :          * If the running system does not support O_TMPFILE flag then retry
     113             :          * without it.
     114             :          */
     115           4 :         if (fd != -1 || (errno != EINVAL && errno != EISDIR &&
     116             :                         errno != EOPNOTSUPP))
     117             :                 return fd;
     118             : #endif
     119             : 
     120           0 :         tempname = malloc(strlen(tempdir) + strlen(template) + 1);
     121           0 :         if (tempname == NULL)
     122             :                 return -1;
     123             : 
     124           0 :         strcpy(tempname, tempdir);
     125           0 :         strcat(tempname, template);
     126           0 :         fd = mkstemp(tempname);
     127           0 :         if (fd < 0) {
     128           0 :                 os_warn("open - cannot create %s: %s\n", tempname,
     129             :                         strerror(errno));
     130           0 :                 goto out;
     131             :         }
     132           0 :         if (unlink(tempname) < 0) {
     133           0 :                 perror("unlink");
     134             :                 goto close;
     135             :         }
     136           0 :         free(tempname);
     137           0 :         return fd;
     138             : close:
     139           0 :         close(fd);
     140             : out:
     141           0 :         free(tempname);
     142           0 :         return -1;
     143             : }
     144             : 
     145             : #define TEMPNAME_TEMPLATE "/vm_file-XXXXXX"
     146             : 
     147           4 : static int __init create_tmp_file(unsigned long long len)
     148             : {
     149             :         int fd, err;
     150             :         char zero;
     151             : 
     152           4 :         fd = make_tempfile(TEMPNAME_TEMPLATE);
     153           4 :         if (fd < 0)
     154           0 :                 exit(1);
     155             : 
     156             :         /*
     157             :          * Seek to len - 1 because writing a character there will
     158             :          * increase the file size by one byte, to the desired length.
     159             :          */
     160           4 :         if (lseek64(fd, len - 1, SEEK_SET) < 0) {
     161           0 :                 perror("lseek64");
     162           0 :                 exit(1);
     163             :         }
     164             : 
     165           4 :         zero = 0;
     166             : 
     167           4 :         err = write(fd, &zero, 1);
     168           4 :         if (err != 1) {
     169           0 :                 perror("write");
     170           0 :                 exit(1);
     171             :         }
     172             : 
     173           4 :         return fd;
     174             : }
     175             : 
     176           2 : int __init create_mem_file(unsigned long long len)
     177             : {
     178             :         int err, fd;
     179             : 
     180           2 :         fd = create_tmp_file(len);
     181             : 
     182           2 :         err = os_set_exec_close(fd);
     183           2 :         if (err < 0) {
     184           0 :                 errno = -err;
     185           0 :                 perror("exec_close");
     186             :         }
     187           2 :         return fd;
     188             : }
     189             : 
     190           2 : void __init check_tmpexec(void)
     191             : {
     192             :         void *addr;
     193           2 :         int err, fd = create_tmp_file(UM_KERN_PAGE_SIZE);
     194             : 
     195           2 :         addr = mmap(NULL, UM_KERN_PAGE_SIZE,
     196             :                     PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
     197           2 :         os_info("Checking PROT_EXEC mmap in %s...", tempdir);
     198           2 :         if (addr == MAP_FAILED) {
     199           0 :                 err = errno;
     200           0 :                 os_warn("%s\n", strerror(err));
     201           0 :                 close(fd);
     202           0 :                 if (err == EPERM)
     203           0 :                         os_warn("%s must be not mounted noexec\n", tempdir);
     204           0 :                 exit(1);
     205             :         }
     206           2 :         os_info("OK\n");
     207           2 :         munmap(addr, UM_KERN_PAGE_SIZE);
     208             : 
     209           2 :         close(fd);
     210           2 : }

Generated by: LCOV version 1.14